Debugs Salesforce issues like Apex exceptions, governor limit breaches, and Flow failures using debug logs, SOQL explain plans, SF CLI tailing, and Developer Console.
npx claudepluginhub jiten-singh-shahi/salesforce-claude-code --plugin salesforce-claude-codeThis skill uses the workspace's default tool permissions.
Reference: @../_reference/DEBUGGING_TOOLS.md
Applies advanced Salesforce debugging via debug logs, SOQL query plans, and EventLogFile analysis for governor limits, slow queries, and complex bugs.
Writes and debugs Apex code, builds Lightning Web Components, optimizes SOQL queries, implements triggers, batch jobs, platform events, and Salesforce integrations. Use for CRM workflows, governor limits, bulk processing, and Salesforce DX CI/CD.
Provides patterns for Salesforce platform development: Lightning Web Components (LWC), Apex triggers/classes, REST/Bulk APIs, Connected Apps, Salesforce DX with scratch orgs and 2GP.
Share bugs, ideas, or general feedback.
Reference: @../_reference/DEBUGGING_TOOLS.md
Via SF CLI (stream live logs):
# Stream all logs for the org in real time
sf apex tail log --target-org myOrg
# Stream logs with specific debug level
sf apex tail log \
--target-org myOrg \
--debug-level SFDC_DevConsole
# Retrieve a specific log by ID
sf apex get log \
--log-id 07L5e000000XXXXX \
--target-org myOrg
# List recent logs
sf apex list log --target-org myOrg
# Run anonymous Apex and capture log
sf apex run \
--file scripts/apex/debug-script.apex \
--target-org myOrg
# Run and save full log
sf apex run \
--file scripts/apex/debug-script.apex \
--target-org myOrg > debug-output.txt
Via Setup UI:
Via Developer Console:
sf org open --target-org myOrgDebug logs have a maximum size of 20 MB. Logs exceeding this are truncated from the middle. If you see gaps, reduce log level verbosity or narrow the operation scope.
15:23:01.001 (1234567)|EXECUTION_STARTED
15:23:01.012 (12345678)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
15:23:01.015 (15000000)|SOQL_EXECUTE_BEGIN|[12]|Aggregations:0|SELECT Id FROM Account
15:23:01.045 (45000000)|SOQL_EXECUTE_END|[12]|Rows:150
15:23:01.050 (50000000)|USER_DEBUG|[15]|DEBUG|Processing 150 accounts
15:23:01.200 (200000000)|DML_BEGIN|[22]|Op:Insert|Type:Contact|Rows:150
15:23:01.350 (350000000)|DML_END|[22]
15:23:01.400 (400000000)|CUMULATIVE_LIMIT_USAGE
Number of SOQL queries: 3 out of 100
Number of DML rows: 150 out of 10000
Maximum CPU time: 452 out of 10000
15:23:01.401 (401000000)|EXECUTION_FINISHED
Compare timestamps between BEGIN/END pairs to identify slow operations:
# Find slow operations by comparing BEGIN/END timestamps
grep -E "SOQL_EXECUTE_BEGIN|SOQL_EXECUTE_END|DML_BEGIN|DML_END" debug.log
// Open Developer Console > Execute Anonymous (Ctrl+E / Cmd+E)
Account acc = [SELECT Id FROM Account WHERE Name = 'Test Corp' LIMIT 1];
AccountService svc = new AccountService();
AccountService.AccountResult result = svc.getAccount(acc.Id);
System.debug(LoggingLevel.ERROR, JSON.serializePretty(result));
-- Developer Console > Query Editor tab
SELECT Id, Name, StageName, Amount, CloseDate
FROM Opportunity
WHERE StageName = 'Negotiation'
AND CloseDate = THIS_QUARTER
ORDER BY Amount DESC
LIMIT 25
Use "Query Plan" button to analyse query performance (see SOQL Query Plan section below).
-- BAD: Cost = 2.5 (TableScan)
SELECT Id FROM Account WHERE Description LIKE '%enterprise%'
-- GOOD: Cost = 0.1 (Index on ExternalId__c)
SELECT Id FROM Account WHERE ExternalId__c = 'ACC-001'
-- GOOD: Cost = 0.3 (Index on OwnerId)
SELECT Id FROM Account WHERE OwnerId = :currentUserId
Available in all editions with the Salesforce Extension Pack:
.log file in VS Code.cls filesRequires Performance Edition, Unlimited Edition, or Enterprise Edition add-on. Not available in Developer Edition.
// .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Apex Debugger",
"type": "apex",
"request": "launch",
"userIdFilter": [],
"requestTypeFilter": [],
"entryPointFilter": "",
"salesforceProject": "${workspaceRoot}"
}
]
}
.cls files (click gutter)Root cause: SOQL query inside a loop
// WRONG -- SOQL in loop
for (Account acc : Trigger.new) {
List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :acc.Id];
}
// FIX -- single query outside loop
Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>();
for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :Trigger.newMap.keySet()]) {
if (!contactsByAccount.containsKey(c.AccountId)) {
contactsByAccount.put(c.AccountId, new List<Contact>());
}
contactsByAccount.get(c.AccountId).add(c);
}
Root cause: Complex nested loops, excessive string operations
// WRONG -- O(n^2) loop
for (Account acc : accounts) {
for (Contact con : allContacts) {
if (con.AccountId == acc.Id) { /* ... */ }
}
}
// FIX -- use Map for O(1) lookup
Map<Id, List<Contact>> contactsByAccount = buildContactMap(allContacts);
for (Account acc : accounts) {
List<Contact> accountContacts = contactsByAccount.get(acc.Id);
}
Root cause: Unchecked null reference
// PREFERRED (API 56.0+) -- null-safe navigation
String upperName = account.Name?.toUpperCase() ?? '';
String accountName = contact?.Account?.Name ?? 'No Account';
Root cause: Two concurrent transactions updating the same record(s). Fix with retry logic (Queueable), FOR UPDATE in SOQL, or reducing batch size.
Root cause: Setup objects (User, Profile) and non-setup objects in the same transaction. Separate with @future or System.runAs() in tests.
Root cause: DML on >10,000 records. Use Batch Apex to process in chunks.
Root cause: Synchronous callout in trigger context. Use @future(callout=true).
| Error | Root Cause | Fix |
|---|---|---|
| "An unhandled fault has occurred" | Missing fault connectors | Add fault paths on all DML/callout elements |
| Flow SOQL 101 limit exceeded | Get Records inside a loop | Move Get Records outside loop, use Collection Filtering |
| "This flow can't access the variable" | Variable not marked for input/output | Enable "Available for input/output" on the variable |
import { LightningElement, wire } from 'lwc';
export default class AccountCard extends LightningElement {
connectedCallback() {
console.group('AccountCard mounted');
console.log('accountId:', this.accountId);
console.groupEnd();
}
handleError(error) {
console.error('AccountCard error:', JSON.stringify(error));
}
}
Install "Salesforce Inspector Reloaded" for real-time metadata browsing, direct record access, API Inspector, and SOQL query runner.
public class DebugCalloutService {
public static HttpResponse send(HttpRequest req) {
System.debug(LoggingLevel.INFO, 'CALLOUT REQUEST: ' + req.getMethod() + ' ' + req.getEndpoint());
System.debug(LoggingLevel.FINE, 'REQUEST BODY: ' + req.getBody());
Http http = new Http();
HttpResponse res = http.send(req);
System.debug(LoggingLevel.INFO, 'CALLOUT RESPONSE: ' + res.getStatusCode());
System.debug(LoggingLevel.FINE, 'RESPONSE BODY: ' + res.getBody());
return res;
}
}
With CALLOUT: FINE level enabled:
CALLOUT_REQUEST|....|POST https://api.example.com/orders
CALLOUT_RESPONSE|....|200 {"orderId":"123","status":"OK"}
sf-review-agent -- for interactive, in-depth guidancesf-apex-constraints -- governor limits and Apex coding rules