Loading

SOQL Subquery Row Limit When Selecting Long Text Area or Rich Text Area Fields

Julkaisupäivä: Jun 10, 2026
Kuvaus

Symptom:

Apex code that traverses child records via a SOQL subquery throws: System.QueryException: Aggregate query has too many rows for direct assignment, use FOR loop

This occurs when Long Text Area (LTA) or Rich Text Area (RTA) fields are selected anywhere in the query tree. Importantly, subqueries that don't themselves select any LTA/RTA fields can also be affected — even within the same query — because the row budget is shared across the entire query tree.

 

Description:

When a SOQL query selects LTA or RTA fields anywhere in the query tree (parent or subqueries), the runtime computes a single memory budget — totalClobLength — by summing the declared max_length of every LTA/RTA field selected across the entire query. This shared budget is applied as a row limit across all subqueries on the parent — it is NOT scoped to only the LTA/RTA-bearing subquery.

 

Key behaviors:

- The budget is computed once, tree-wide, not per subquery.

- The reduced row budget is shared across all sibling subqueries and parent rows.

- A subquery that selects no LTA/RTA fields of its own can still be truncated and throw on direct assignment, purely because a sibling subquery's LTA/RTA fields wound the shared budget down.

- The effective memory ceiling is approximately 16–32 MB (power-of-two rounding causes it to oscillate in this band).

- A ~200-row floor provides some safety, but this applies to the combined child rows materialised across all subqueries — not each subquery in isolation. Several subqueries each under 200 rows can still collectively exceed the shared cap.

 

Note: totalClobLength is internal runtime behavior, not a documented public contract. These thresholds can change between releases and should be treated as planning heuristics, not guarantees.

Ratkaisu

Workaround:

Use a SOQL for loop over both the parent and child to avoid direct list assignment:

// Risky — direct list assignment can exceed the shared row budget

List<Child__c> items = record.getSObjects('ChildRelationship__r');


// Safe — iterate with a SOQL for loop over parent and child

for (Parent__c p : [ SELECT Id, (SELECT Id, Long_Text__c FROM ChildRelationship__r)

                    FROM Parent__c WHERE ...]) {

   for (Child__c c : p.ChildRelationship__r) {

       // process — safe in the select-loop context

   }

}

CPU Timeout Caveat: The SOQL FOR loop workaround may avoid the QueryException but for large data volumes, iterating over large number of  parent records with LTA-heavy child rows can consume  CPU and risk hitting the 10,000ms Apex CPU timeout limit.

 

Alternatively, restructure the query to separate the LTA-heavy subquery into its own standalone SOQL query with a WHERE clause to limit results.

See Salesforce Apex Developer Guide — SOQL For Loops for more details.

    Long-term resolution:

    Keep the combined child rows materialised across all subqueries under the (LTA-reduced) budget. If data volume cannot be controlled, use the SOQL for loop pattern or split the query.

    Knowledge-artikkelin numero

    005386638

     
    Ladataan
    Salesforce Help | Article