home Homebuild Toolsbug_report Errorsmenu_book Guideslightbulb Tipssmart_toy Promptsextension Extensionsfolder_open Resourcesinfo About
search
error

System.QueryException: Aggregate query has too many rows for direct assignment, use FOR loop

What does this error mean?

When an aggregate SOQL query (one using GROUP BY or aggregate functions) returns more than 2,000 rows, Salesforce does not allow direct assignment to a List<AggregateResult> variable. The direct assignment would require loading all 2,000+ rows into memory simultaneously, which Salesforce guards against. The solution is to use a SOQL for-loop, which processes aggregate results in chunks.

Common Causes

1. High-cardinality GROUP BY field

Grouping by a field with many distinct values (e.g., GROUP BY OwnerId in a large org with thousands of users, or GROUP BY External_Id__c on a high-volume object) produces more than 2,000 groups.

2. No LIMIT clause on aggregate query

An aggregate query without a LIMIT that returns an unexpectedly large number of distinct groups as data grows over time.

How to Fix It

Solution 1: Use a SOQL for-loop for large aggregate results

Apex
// ❌ BAD — fails if more than 2,000 groups
List<AggregateResult> results = [
    SELECT OwnerId, SUM(Amount) total
    FROM Opportunity
    GROUP BY OwnerId
];

// ✅ GOOD — for-loop handles any number of groups
Map<Id, Decimal> totalByOwner = new Map<Id, Decimal>();
for (AggregateResult ar : [
    SELECT OwnerId, SUM(Amount) total
    FROM Opportunity
    GROUP BY OwnerId
]) {{
    totalByOwner.put(
        (Id) ar.get('OwnerId'),
        (Decimal) ar.get('total')
    );
}}

Solution 2: Add a LIMIT clause if you only need top results

Apex
// If you only need the top N groups, add LIMIT
List<AggregateResult> top10 = [
    SELECT OwnerId, SUM(Amount) total
    FROM Opportunity
    GROUP BY OwnerId
    ORDER BY SUM(Amount) DESC
    LIMIT 10
];