System.DmlException: Insert failed. First exception on row 0; first error: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id: []
What does this error mean?
This error occurs when Apex code (or an automated process) attempts to create or update a record that references another record the running user does not have read or edit access to. Salesforce enforces record-level security even in system context operations that involve cross-object relationships.
The phrase "cross-reference entity" refers to a lookup or master-detail field pointing to a record in another object. If the running user cannot see that target record, the DML fails with this error.
Important: This error fires based on the running user's access — not the org's OWD or the system admin's access. In triggers, the running user is whoever performed the triggering action. In scheduled jobs or future methods, it is the user who scheduled or invoked the job.
Common Causes
1. Lookup to a Record the User Cannot See
The most common cause. A trigger or automation creates a record with a lookup field pointing to a record (e.g., an Account) that the running user's sharing rules restrict. Even if the running user can create the child record, they cannot link it to a parent they cannot view.
2. OWD Set to Private on the Parent Object
When the Organisation-Wide Default (OWD) for a parent object is set to Private, users only see records they own (or that sharing rules explicitly share with them). A lookup to a privately-owned record owned by another user will fail for users who don't have access.
3. Running in User Mode Without Sufficient Access
Code that runs in User Mode (WITH USER_MODE SOQL clause or the AccessLevel.USER_MODE DML flag) inherits the running user's CRUD and FLS. If that user lacks access to the referenced record, the DML fails.
4. Flow or Process Builder Automation
Record-triggered flows run in system context by default, but flows launched via user interaction (screen flows, quick actions) run as the current user. A cross-object update in a user-context flow can trigger this error for restricted users.
5. Integration User with Restricted Profile
API integrations using a dedicated integration user profile may lack the sharing access required to reference records owned by other users, causing failures when creating related records.
| Scenario | Root Cause | Fix Approach |
|---|---|---|
| Trigger creates child record with Account lookup | OWD = Private on Account; running user doesn't own it | Add sharing rule or use without sharing |
| Flow updates Opportunity related to restricted Account | User-context flow, user lacks Account access | Grant sharing or reconfigure flow context |
| Integration creates Case with Contact lookup | Integration user profile doesn't see Contact | Adjust integration user sharing settings |
Database.update(record, AccessLevel.USER_MODE) |
Explicit user-mode DML, user lacks access | Switch to SYSTEM_MODE or fix user's access |
How to Fix It
Solution 1: Use without sharing on the Handler Class
If your Apex logic is intentionally designed to operate with elevated access (e.g., system automation that should bypass record-level security), declare the class without sharing. Use this carefully — it bypasses all sharing rules for that class's execution.
// Explicitly bypass sharing — use only when appropriate
public without sharing class CaseCreationService {
public static void createRelatedCases(List<Account> accounts) {
List<Case> cases = new List<Case>();
for (Account acc : accounts) {
cases.add(new Case(
AccountId = acc.Id,
Subject = 'Auto-generated: ' + acc.Name,
Status = 'New'
));
}
insert cases;
}
}
Solution 2: Diagnose Errors with Database.insert(allOrNone:false)
Use partial DML with allOrNone = false to isolate which records are failing and log meaningful error information instead of letting the whole transaction roll back.
List<Database.SaveResult> results =
Database.insert(recordsToInsert, false);
for (Integer i = 0; i < results.size(); i++) {
if (!results[i].isSuccess()) {
for (Database.Error err : results[i].getErrors()) {
if (err.getStatusCode() ==
StatusCode.INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY) {
System.debug('Access error on record: '
+ recordsToInsert[i].Id
+ ' — ' + err.getMessage());
}
}
}
}
Solution 3: Add a Sharing Rule for the Referenced Object
If the OWD is Private and you need certain users or groups to see specific records, configure sharing rules in Setup. This is the safest approach — it preserves your security model while granting the required access.
Go to Setup → Security → Sharing Settings, find the object with OWD set to Private, and under Sharing Rules click New. Define the criteria (owner or record criteria) and grant Read or Read/Write access to the appropriate user group, role, or territory.
Solution 4: Use System.runAs() in Tests to Reproduce
Always write tests that reproduce the sharing scenario to confirm your fix works correctly under the actual user context.
@isTest
private class CaseCreationServiceTest {
@isTest
static void testCreateAsRestrictedUser() {
// Create a user with a restricted profile
User restrictedUser = [
SELECT Id FROM User
WHERE Profile.Name = 'Standard User'
LIMIT 1
];
Account acc = new Account(Name = 'Test Corp');
insert acc;
// Simulate running as the restricted user
System.runAs(restrictedUser) {
Test.startTest();
CaseCreationService.createRelatedCases(
new List<Account>{ acc }
);
Test.stopTest();
}
List<Case> cases = [SELECT Id FROM Case];
System.assertEquals(1, cases.size(), 'Case should be created');
}
}
Pro Tip: Use Salesforce Inspector or Setup → Permission Set Assignments to quickly check what record access a specific user has. The User Access Summary in Setup (Lightning) shows exactly which sharing rules apply to a given user for any object.