System.LimitException: Too many aggregate queries: 301
What does this error mean?
Salesforce tracks aggregate SOQL queries — those using GROUP BY, COUNT(), SUM(), AVG(), MIN(), MAX() — separately from standard queries. The limit is 300 aggregate queries per transaction (synchronous and asynchronous alike). Aggregate queries also count toward the standard 100 SOQL query limit, so hitting this limit means you've likely already hit or are near the 100 SOQL limit too.
Common Causes
1. Aggregate queries inside loops
Running a COUNT() or SUM() query per record in a loop is the classic cause. With 200 records in a trigger, that's 200 aggregate queries — already well past the limit in asynchronous contexts and over it in synchronous.
2. Complex reporting logic in Apex
Analytics or rollup logic that runs multiple GROUP BY queries across different field combinations — for example, grouping by region, then by owner, then by stage — quickly accumulates aggregate query count.
How to Fix It
Solution 1: Combine aggregate queries with IN clauses
Instead of one aggregate query per record, write a single aggregate query that covers all records and use a Map to distribute results.
// ❌ BAD — aggregate query per account
for (Account acc : Trigger.new) {{
AggregateResult ar = [
SELECT SUM(Amount) total
FROM Opportunity
WHERE AccountId = :acc.Id
][0];
}}
// ✅ GOOD — single aggregate for all accounts
Map<Id, Decimal> totals = new Map<Id, Decimal>();
for (AggregateResult ar : [
SELECT AccountId, SUM(Amount) total
FROM Opportunity
WHERE AccountId IN :Trigger.newMap.keySet()
GROUP BY AccountId
]) {{
totals.put((Id)ar.get('AccountId'), (Decimal)ar.get('total'));
}}
Solution 2: Use roll-up summary fields for simple totals
If you're aggregating child records to a parent, consider using a Salesforce Roll-Up Summary Field instead of Apex. These update automatically via the platform without consuming governor limits.
Pro Tip: Aggregate queries also count toward the standard 100 SOQL limit. Use Limits.getAggregateQueries() to track aggregate query usage and Limits.getQueries() to monitor total query count simultaneously.