Salesforce throws a “Record Locked” or UNABLE_TO_LOCK_ROW error when two or more operations attempt to update the same record—or its related parent record—at the exact same time. This error occurs during automated background jobs, high-volume bulk imports, continuous API synchronizations, or parallel Apex processes. When the Salesforce platform cannot obtain an exclusive database lock within a brief timeout window (typically 10 seconds), it rejects the incoming update to protect data integrity.
Fast Fix
Identify the parent record causing the lock conflict. If running bulk API imports, switch the Bulk API job mode from Parallel to Serial, or sort incoming batch rows by
AccountIdor common parent lookup IDs. This stops concurrent threads from competing for the same parent row simultaneously.
Diagnostic Snapshot
- Error Signatures:
UNABLE_TO_LOCK_ROW: unable to obtain exclusive access to this record,Record Currently Unavailable,CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY. - Primary Scope: Asynchronous Apex, integrations, bulk data loads, and complex automation (Apex triggers, Flows).
- Core Mechanism: Relational row locking on parent records to maintain data consistency.
- Access Needed: System Administrator or Developer Console access to inspect Apex jobs, Flow definitions, and Bulk API settings.
Understanding the Lock Mechanism
Salesforce relies on an underlying relational database engine. Whenever an update begins on a child record, the platform frequently locks the parent record as well.
Locks occur automatically in scenarios such as:
- Editing a Contact or Opportunity (locks the associated
Account). - Inserting or updating a child object in a Master-Detail relationship (locks the master record to maintain roll-up summary values).
- Modifying user roles or public group memberships (locks system-level sharing tables).
- Assigning records that alter territory or sharing hierarchies.
If Thread A updates a Contact under “Acme Corp” and simultaneously Thread B updates an Opportunity under “Acme Corp,” both threads demand an exclusive lock on the “Acme Corp” Account row. If Thread A takes longer than 10 seconds—due to heavy trigger logic, multiple Record-Triggered Flows, or downstream roll-ups—Thread B fails and throws UNABLE_TO_LOCK_ROW.
Diagnostic Path: Pinpoint the Conflicting Operations
Is the failure occurring in UI, Bulk Load, or Scheduled Automation?
├── Bulk API / Data Loader ─────► Inspect batch concurrency (Parallel vs. Serial)
│ Check for shared parent ID clustering
├── Apex / Integration ─────────► Check Apex debug logs for FOR UPDATE statements
│ Evaluate long-running DML transactions
└── UI / Manual Save ───────────► Check active approval processes
Inspect real-time background callouts/triggers
Step 1: Check Execution Mode and Concurrency
- Bulk Data Loader / Integrations: If using Bulk API 2.0 or third-party middleware (such as MuleSoft, Zapier, or native connectors), check whether records are submitted in parallel chunks. If 5,000 child records reference the same ten accounts across parallel threads, collision is guaranteed.
- Asynchronous Apex (Queueable / Batch Apex): Look at your batch size in
Database.executeBatch(instance, scope). A high scope (e.g., 200 records) executing heavy synchronous DML can hold locks longer than expected.
Step 2: Trace the Locked ID in Debug Logs
When UNABLE_TO_LOCK_ROW appears, the error message lists a specific Salesforce 15- or 18-character record ID:UNABLE_TO_LOCK_ROW: unable to obtain exclusive access to this record 001XXXXXXXXXXXX
Paste that ID into your browser navigation bar (yourInstance.lightning.force.com/lightning/r/Account/001XXXXXXXXXXXX/view).
- Is this ID the record you were updating, or is it a parent Account, custom master record, or lookup target?
- If it is a parent record, your problem is not the record you were sending—it is lock contention on the relational parent.
Resolution Steps
Method 1: Sort Import Files by Parent ID
When performing bulk inserts or updates:
- Open your CSV source file.
- Sort the data ascending or descending by the parent lookup column (such as
AccountIdorParent_Project__c). - Process the file.
Why this works: When records sharing the same parent are grouped together into identical batches, a single thread updates them sequentially rather than multiple parallel threads fighting for the same parent record lock across different batches.
Method 2: Force Serial Mode in Data Tools
If parent sorting does not eliminate the contention:
- Salesforce Data Loader: Go to Settings > toggle Enable Bulk API > select Enable serial processing for Bulk API.
- Third-Party ETLs: Set worker thread concurrency to
1or selectSerialprocessing mode in your endpoint configuration. If dealing with delays in integration queues, review Troubleshooting: CRM “Sync Queue” Backlog – Resolving 4-hour delays.
Method 3: Refactor Apex FOR UPDATE and DML Chains
If custom Apex code is failing:
- Remove unnecessary explicit row locks: Avoid using
SELECT ... FOR UPDATEunless strict transaction locking is absolutely required. - Shorten transaction execution time: Keep callouts, extensive business logic, and complex queries out of the transaction block where DML operations are executed.
- Avoid redundant updates: Ensure triggers do not issue unnecessary DML statements on parent records when values have not changed. If Apex run times are dragging down performance, see Fix: Salesforce “Apex CPU Time Limit Exceeded” (Error 1001).
// Anti-Pattern: Locking parent row during long calculations
Account acc = [SELECT Id FROM Account WHERE Id = :accId FOR UPDATE];
runHeavyCalculation(); // Locks Account during this entire time
update acc;
// Better Pattern: Minimize lock duration
runHeavyCalculation();
Account acc = [SELECT Id FROM Account WHERE Id = :accId];
acc.Status__c = 'Calculated';
update acc; // Lock held only for milliseconds
Method 4: Audit Record-Triggered Flows and Roll-Up Summaries
Roll-up Summary fields on master records require row locks on the master record whenever child records are altered.
- Audit your custom objects: If a single parent record has thousands of child records, it is a data skew candidate.
- Convert excessive real-time Roll-Up Summary fields or Record-Triggered Flows into scheduled, asynchronous recalculation jobs running off-peak.
- Check if flows are recursively calling parent updates using How to Resolve: Salesforce “Flow” stuck in an Infinite Recursive Loop.
Hard Stops and Architectural Red Flags
Stop basic troubleshooting and review your data architecture if you encounter Account Data Skew or Ownership Skew:
- Account Data Skew: A single Account record has more than 10,000 child Contacts, Opportunities, or custom objects. Even basic daily updates will trigger continuous locking timeouts. The architectural fix requires redistributing children across multiple dummy/holding accounts.
- Ownership Skew: A single system user owns tens of thousands of records within a role hierarchy. Any change to role permissions, sharing rules, or territory models will lock massive swaths of the database.