Hello again. In the previous lesson, you traced record access from object and field permissions through organization-wide defaults, hierarchy access, sharing rules, teams, and manual sharing. That was a who can access which record diagnosis.
This lesson shifts to a different kind of production diagnosis: a transaction that fails because it consumed too much of a shared Salesforce resource. Debug-log interpretation is a practical skill for developer work and a frequent interview prompt. By the end, you will be able to identify the specific governor limit responsible for a failure, distinguish it from an ordinary application error, and locate the operation or automation most likely responsible.
Governor limits are transaction budgets
Salesforce is a multi-tenant platform: many organizations share underlying infrastructure. A governor limit is therefore a hard budget for a resource used during one transaction, such as database queries, DML operations, CPU time, heap memory, or callouts.
A transaction is one unit of work. For example, saving one Account can invoke validation rules, record-triggered Flows, Apex triggers, and additional DML on related records. Their resource use contributes to the same transaction budget.
Watch this short introduction for the platform rationale.
Apex Governor Limits | Chapter 91 | Salesforce Developer Masterclass
Watch “Apex Governor Limits” by Salesforce Makes Sense for the core reason governor limits exist: Salesforce allocates finite shared resources across tenants.
Watch the foundation. Focus on the idea of a fixed per-transaction ceiling rather than trying to memorize every possible limit.
Two consequences matter during debugging:
- Limits are cumulative. Ten queries in a Flow, ninety-one queries in Apex, and a query in a trigger can collectively breach the synchronous SOQL-query limit.
- A limit breach fails the transaction. The transaction is rolled back; prior DML work in that transaction does not persist. The log, however, still records the resource consumption that led to the failure.
For common synchronous Apex transactions, these are the signatures worth recognizing first:
| Resource | Typical synchronous ceiling | Failure wording to recognize |
|---|---|---|
| SOQL queries | 100 | Too many SOQL queries: 101 |
| SOQL query rows | 50,000 | Too many query rows: 50001 |
| DML statements | 150 | Too many DML statements: 151 |
| DML rows | 10,000 | Too many DML rows: 10001 |
| CPU time | 10,000 ms | Apex CPU time limit exceeded |
| Heap size | 6 MB | Apex heap size too large |
| Callouts | 100 | Too many callouts: 101 |
The exact ceilings can differ by execution context—for example, asynchronous jobs have different limits. When analyzing a real incident, treat the exception text and the limit shown in that log as the authority.
A useful distinction:
- A SOQL query limit counts statements issued.
- A query-row limit counts records returned across queries.
- A DML statement limit counts DML operations such as
insert,update,delete, orDatabase.update. - A DML-row limit counts records affected.
One bulk update accountsToUpdate; may use one DML statement but affect hundreds of DML rows. This distinction prevents a common incorrect diagnosis.
Learn the log’s structure before chasing the failure
A raw debug log is chronological. Its lines record execution events, including code-unit boundaries, SOQL, DML, Flow or validation activity, debug statements, exceptions, and usage snapshots.

In the screenshot, the LIMIT_USAGE_FOR_NS entries show consumption such as “Number of SOQL queries: 19 out of 100.” The lower Limits panel presents the same information in a summary form. Modern tooling and raw logs may look different, but the key labels remain useful.
Read this concise orientation to the useful boundaries in a log.
How do I start debugging an error in Salesforce? | Thinqloud
Read Thinqloud’s explanation of execution units and cumulative resource usage. It gives you a mental map for locating the transaction-wide evidence rather than interpreting a single line in isolation.
In the “Execution Units” discussion, read the cumulative-usage explanation. Notice that a trigger, test method, anonymous execution, or asynchronous execution can form a meaningful diagnostic boundary, while the whole transaction may contain several nested code units.
The event names to recognize are:
| Log event | What it tells you |
|---|---|
EXECUTION_STARTED / EXECUTION_FINISHED | Outer boundary of the transaction |
CODE_UNIT_STARTED / CODE_UNIT_FINISHED | A trigger, class, Flow-related unit, test method, or other unit of work began or ended |
SOQL_EXECUTE_BEGIN / SOQL_EXECUTE_END | A database query ran; the end entry commonly reports returned rows |
DML_BEGIN / DML_END | A DML operation was attempted or completed |
LIMIT_USAGE_FOR_NS | A resource-usage snapshot for a namespace |
CUMULATIVE_LIMIT_USAGE | A transaction-level usage summary, when present |
EXCEPTION_THROWN / FATAL_ERROR | The direct failure evidence |
USER_DEBUG lines can provide helpful landmarks, but they are not proof of what failed. A line such as USER_DEBUG|DEBUG|starting update merely tells you where custom logging happened. The decisive evidence is normally the exception line.
A reliable diagnosis method
When a user reports a failure, do not start by counting every SOQL or DML line manually. Use this sequence instead.
1. Confirm that it is a governor-limit failure
Search the raw log for these terms, in this order:
FATAL_ERRORLimitExceptionToo manyCPU timeheapLIMIT_USAGE_FOR_NS
A governor-limit failure generally contains System.LimitException or a clear platform limit message. Contrast it with:
FIELD_CUSTOM_VALIDATION_EXCEPTION, which is a validation-rule failure;DUPLICATE_VALUE, which is a duplicate-record error;System.QueryException, which may be malformed SOQL or an unexpected query result;System.DmlException, which may wrap a field, validation, or sharing-related DML problem.
Those errors can be serious, but they are not automatically governor-limit failures.
2. Read the exception literally
Suppose the end of a log contains:
EXCEPTION_THROWN|[42]|System.LimitException: Too many SOQL queries: 101
FATAL_ERROR|System.LimitException: Too many SOQL queries: 101
The responsible limit is the SOQL-query statement limit. The number 101 tells you the transaction attempted its 101st query in a synchronous context where the ceiling was 100.
You do not need to infer that this is a “performance problem” in general. State the precise finding:
The transaction failed because it exceeded the SOQL-query governor limit: it attempted 101 queries where 100 were permitted.
That level of specificity is what a reviewer, interviewer, or incident ticket needs.
3. Cross-check the usage summary—but do not let it overrule the exception
Look for CUMULATIVE_LIMIT_USAGE or LIMIT_USAGE_FOR_NS near the end of the log. You might see:
Number of SOQL queries: 100 out of 100
Number of DML statements: 12 out of 150
Maximum CPU time: 1840 out of 10000
This supports the SOQL diagnosis. It also rules out DML or CPU as the primary failure.
However, a snapshot can show 100 out of 100 even though the exception says “Too many SOQL queries: 101.” The 101st attempt failed, so it may not appear as a completed, counted operation in every summary. When they appear to differ, trust the explicit System.LimitException message for the failure cause.
4. Move upward from the exception to find the immediate trigger
The line number in an exception is often the most direct clue:
EXCEPTION_THROWN|[42]|System.LimitException: Too many DML statements: 151
Look upward for the enclosing CODE_UNIT_STARTED entry. It tells you whether the failing instruction came from:
- an Apex class or trigger;
- a test method;
- a Visualforce controller;
- a Flow-related code path;
- another automation layer.
Then inspect the immediately preceding relevant operations. Before a SOQL failure, find the final SOQL_EXECUTE_BEGIN. Before a DML failure, find the final DML_BEGIN.
This identifies the failing instruction, not necessarily the whole design defect. The 101st query is simply where the transaction ran out of budget; the earlier hundred queries may have come from multiple triggers, handlers, or Flows.
5. Trace the cumulative path, not only the last line
After locating the immediate failure, work backward through the transaction’s major code units. Ask:
- Which automation began this transaction?
- What additional triggers or Flows ran because of DML?
- Is the same handler or query pattern repeated?
- Does the log show a query or DML operation inside repeated execution?
The prior lesson’s order-of-execution context matters here: a record update can activate several automation mechanisms. A class may have only twenty SOQL queries on its own, but it can still be part of a transaction that has already consumed eighty-one through other automation.
Recognizing the usual failure patterns
The failure text identifies which budget was exceeded. The surrounding log points to why it happened.
| Observed failure | What the log usually shows | Likely underlying pattern |
|---|---|---|
| Too many SOQL queries | Repeated SOQL_EXECUTE_BEGIN entries, often in the same code unit | Query inside a loop; several automations querying the same records independently |
| Too many query rows | One or more SOQL_EXECUTE_END entries with very large row counts | Unselective query; querying an unnecessarily broad relationship or data set |
| Too many DML statements | Repeated DML_BEGIN entries | insert, update, or delete inside a loop; recursive automation |
| Too many DML rows | A bulk operation affects more than 10,000 total records | Automation expands one change into too many related record updates |
| Apex CPU time limit exceeded | Query/DML counts may remain below their ceilings; long execution duration or repeated logic | Nested loops, expensive calculations, recursion, or too much combined automation |
| Apex heap size too large | Frequent or large HEAP_ALLOCATE entries; huge collections or serialized payloads | Loading too many fields/records, retaining data unnecessarily, large JSON or strings |
| Too many callouts | Repeated callout events | One HTTP callout per record rather than batching or redesigning async work |
Watch the log-reading demonstration before examining the examples below.
Debug Logs - Explained | Chapter 92 | Salesforce Developer Masterclass
Watch “Debug Logs - Explained” by Salesforce Makes Sense for a visual walkthrough of timestamps, events, error lines, and limit usage in a debug log.
Watch reading the log. Focus on the relationship between the chronological execution events and the governor-limit usage summary; this is the relationship you will use in every diagnosis.
Pattern A: SOQL inside a loop
Imagine a trigger handling 200 incoming Cases. Its handler loops over Cases and runs a SOQL query once for each Case. The log may show many repeated query events followed by:
EXCEPTION_THROWN|[18]|System.LimitException: Too many SOQL queries: 101
FATAL_ERROR|System.LimitException: Too many SOQL queries: 101
Correct diagnosis: SOQL-query governor limit exceeded.
Probable cause: A query is executed repeatedly, often from inside a loop. The repair is not “raise the limit,” because Apex limits cannot be raised for this transaction. The later Apex module will formalize the refactoring pattern: collect needed IDs in a set, issue one query outside the loop, and use a map for lookup.
Pattern B: DML inside a loop
A second handler constructs one Task for each incoming record and executes insert task; during every loop iteration. The relevant ending may be:
DML_BEGIN|[31]|Op:Insert|Type:Task|Rows:1
EXCEPTION_THROWN|[31]|System.LimitException: Too many DML statements: 151
FATAL_ERROR|System.LimitException: Too many DML statements: 151
Correct diagnosis: DML-statement governor limit exceeded.
Do not call this a “DML row” failure simply because the code inserts records. A DML statement was issued 151 times. The usual correction is to collect all Tasks in a list and insert the list once.
Pattern C: CPU limit without a query or DML limit breach
CPU failures can be more deceptive:
EXCEPTION_THROWN|System.LimitException: Apex CPU time limit exceeded
FATAL_ERROR|System.LimitException: Apex CPU time limit exceeded
The cumulative section might report only 30 SOQL queries and 20 DML statements—comfortably within their independent limits. The failure is still unambiguous: CPU time is the exhausted resource.
Now inspect the execution path for repeated trigger or Flow invocations, nested loops, expensive string or collection processing, and formulas or automation repeatedly recalculated. Avoid the shortcut “there are lots of queries, so it must be SOQL.” A transaction can have many queries and still fail first on CPU.
A compact incident-reporting format
After reviewing the log, communicate the result in three parts:
- Failure: name the exact governor limit and exception text.
- Location: identify the failing code unit, class/method/line if available, and the initiating record action.
- Cause hypothesis: state the observed pattern, separating evidence from inference.
For example:
The Account update transaction failed with
System.LimitException: Too many DML statements: 151. The failure occurred inCaseFollowUpHandler.createTasks, invoked by the Case after-update trigger. The log shows repeated single-rowDML_BEGINinsert operations in that handler, which indicates DML is being performed per record rather than in bulk.
This is stronger than “the trigger has a governor-limits issue.” It is concise, falsifiable, and gives the next developer a useful starting point.
When you have access to Salesforce tooling, begin with a trace flag for the user who reproduces the problem, then retrieve the matching log from Setup, Debug Logs or inspect it in Developer Console. Capture the smallest reproducible action possible. A noisy log containing unrelated user activity makes it much harder to establish the true transaction boundary.
Key takeaways
A governor-limit diagnosis is evidence-led:
- First find
FATAL_ERROR,System.LimitException, or explicit “Too many” wording. - Name the exact resource: SOQL statements, query rows, DML statements, DML rows, CPU time, heap size, or callouts.
- Use
LIMIT_USAGE_FOR_NSandCUMULATIVE_LIMIT_USAGEas confirmation, while treating the exception line as decisive. - Trace upward through
CODE_UNIT_STARTED, SOQL, and DML events to find the immediate instruction and the wider automation chain. - Do not confuse a governor limit with validation, duplicate, sharing, or ordinary query errors.
- Report the failure, location, and evidence-based root-cause hypothesis separately.
Next, you will begin the Apex, SOQL, and transaction-control module by implementing an Apex class with typed methods, constructors, access modifiers, and interfaces.
Can't find a good explanation? Sign up and we'll make it for you
Sign up