Insufficient Privileges. You do not have the level of access necessary to perform the operation you requested.
Object-level access — the user lacks Read/Edit/Create/Delete on the object itself, not on a particular row. Different from "You don't have access to this record" (which is sharing on one row). Granted via profile or permission set; auditable in Setup.
Also seen asInsufficient Privileges·You do not have the level of access necessary·Insufficient Privileges. You do not have
A new sales rep on a Tuesday afternoon clicks an Opportunity link in a Slack message and lands on a Salesforce page that reads "Insufficient Privileges. You do not have the level of access necessary to perform the operation you requested." The same page worked for her yesterday. Her colleagues on the same team can open the record without issue. She refreshes, signs out, signs back in. The page is still blocked. The admin needs to figure out which permission boundary changed.
What the platform is checking
The page-level Insufficient Privileges message fires when the Salesforce UI denies access to a record, an object, or an action. Unlike API errors that name a specific permission, the UI message is intentionally vague. It tells the user the access check failed without explaining which check, to avoid leaking information about the org's permission structure to an unauthenticated or under-privileged user.
The platform runs a layered check before rendering any record page. Each layer can independently produce the Insufficient Privileges screen. The layers are profile object permissions, permission set object permissions, sharing rules, role hierarchy, ownership, restriction rules, field-level security on the URL parameters, the record type assignment, and the page layout assignment.
For records you cannot create, view, edit, or delete due to object permissions, the UI shows the same page as for records you cannot see due to sharing. The admin has to investigate every layer until one matches.
The most common shapes are these. The user lost the profile that granted Read on the object. A permission set that previously granted access was removed. The record's owner changed and the user lost implicit access. A sharing rule was deleted or its criteria changed. The user's role moved in the hierarchy and lost view-through access from a parent role. A restriction rule was added that filters out this specific record type. The record was moved to a record type the user is not assigned to.
The broken example
There is no Apex code that produces this error directly; the error is a UI-level guard that fires before any custom code runs. But the cause often involves an admin change to permissions. A common workflow that produces the message:
The org has a Sales User profile that grants Read on Opportunity. The admin creates a new Sales User v2 profile with stricter permissions and reassigns half the team to it. The new profile omits Read on Opportunity because the admin meant to grant access through a permission set later, then forgot. The reassigned users lose access immediately and see the Insufficient Privileges page on every Opportunity link.
A second shape: an admin adds a restriction rule on Account that filters by Industry. The intent is to hide healthcare accounts from non-healthcare team users. The rule criterion is a formula that contains a typo and inadvertently matches every account. Every non-admin user sees Insufficient Privileges on every Account.
A third shape: the user's role moves in the hierarchy from a manager role to a peer role of the new manager. The old manager owned several records that the user could see via the role hierarchy. After the move, the implicit access through the hierarchy disappears.
A fourth shape: a Lightning page has a custom component that calls an Apex method without @AuraEnabled annotation. The component fails to render and the page renders an Insufficient Privileges fallback, even though the underlying record is accessible.
Why the message is so generic
Salesforce intentionally avoids revealing the specific reason for denial. A page that read "You lack Read on the Opportunity object" would tell an attacker exactly which permission set or profile to attempt to spoof. The vague message is a security-by-obscurity layer that protects the permission model.
The trade-off is that diagnosis is harder. Admins have to walk through the checks systematically. There is no shortcut from the UI; the page does not log the failing check anywhere the end user can see.
The fix, three paths
Add a permission set that grants the missing access. The cleanest fix for a missing object permission or a missing field is a targeted permission set. Permission sets are additive; they grant access without modifying the underlying profile.
Setup → Permission Sets → New → name it for the access it grants ("Opportunity Read", "Healthcare Account Access"). Add the object permissions, field permissions, and any record-type assignments. Assign the permission set to the affected user. The user should see the page after a refresh.
Fix the sharing rule or restriction rule. If the cause is a misconfigured rule, edit the rule. Restriction rules in particular have a "Test" view in Setup that lets you preview which records the rule would expose for a sample user.
Setup → Object Manager → Account → Restriction Rules → select the rule → Edit. Review the criteria carefully. A common gotcha is a NULL value in the filter field that the rule's logic treats as a match. Add explicit OR ISBLANK(...) clauses if blanks should pass.
Restore the role-hierarchy position or transfer ownership. If the cause is a role-hierarchy move, decide whether the move was correct. If yes, the user no longer should have access and the Insufficient Privileges screen is working as intended. If no, restore the role to its prior position.
If ownership has changed and the user needs access to records they no longer own, create a public group, add the user, and write a sharing rule that exposes the records to the group.
The fixed example
A permission-set definition (metadata) that grants Read and Edit on Opportunity along with the necessary field permissions:
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
<description>Sales rep access to Opportunity</description>
<label>Sales Rep Opportunity Access</label>
<objectPermissions>
<allowCreate>true</allowCreate>
<allowDelete>false</allowDelete>
<allowEdit>true</allowEdit>
<allowRead>true</allowRead>
<modifyAllRecords>false</modifyAllRecords>
<object>Opportunity</object>
<viewAllRecords>false</viewAllRecords>
</objectPermissions>
<fieldPermissions>
<editable>true</editable>
<field>Opportunity.Amount</field>
<readable>true</readable>
</fieldPermissions>
<fieldPermissions>
<editable>true</editable>
<field>Opportunity.StageName</field>
<readable>true</readable>
</fieldPermissions>
<recordTypeVisibilities>
<default>true</default>
<recordType>Opportunity.Standard</recordType>
<visible>true</visible>
</recordTypeVisibilities>
</PermissionSet>
Assigning this permission set to the affected user restores access without modifying the user's profile. If the access was granted by mistake, removing the permission set is one click; modifying a profile and reverting is much harder.
Edge case: Insufficient Privileges on Apex actions, not records
A page that calls a Visualforce controller action or an Apex method via Lightning can produce Insufficient Privileges even when the user can see the record. The cause is usually:
- The Apex class is not in the user's enabled-classes list (Setup → Apex Classes → Security).
- The custom permission required by the class is not granted.
- The class itself enforces a check that the user fails.
Setup → Profile or Permission Set → Apex Class Access. Add the failing class. The page should load after the user refreshes.
Edge case: record-type and page-layout mismatches
A record assigned to a record type the user is not eligible for produces Insufficient Privileges when the user navigates to it. The record exists; the user has Read on the object; but the record type filters them out at the UI layer.
Setup → Permission Set → Object Settings → Record Types → ensure the record type is assigned. Add the user's record-type assignment under the permission set.
Edge case: the URL contains a sandbox link in production or vice versa
A user clicking a sandbox URL while logged in to production (or vice versa) lands on a page that doesn't exist in the current org. The error displayed is often Insufficient Privileges rather than a more specific "record not found", because Salesforce uses the same denial page for missing records as for missing access.
Confirm the user is on the correct org instance. The browser URL bar reveals whether they are on na1.salesforce.com (production) or cs1.salesforce.com (sandbox).
Edge case: external users (Communities and Experience Cloud)
Experience Cloud users have separate sharing settings from internal users. An external user who can see an Account on the internal app may not see it on the community page. The cause is typically:
- The External Sharing Model on the object is set to Private.
- No community-specific sharing rule grants access.
- The Account is not in a Channel Program or Partner Network that the user belongs to.
Setup → Sharing Settings → External Sharing Model. Verify the setting. Add an external sharing rule or grant access through the community's role hierarchy.
Test patterns
Permission tests should run as the affected profile, not as an admin.
@IsTest
static void salesUserCanReadOpportunity() {
User salesUser = TestUtil.createUserWithProfile('Sales User');
Opportunity opp = TestUtil.createOpportunity();
System.runAs(salesUser) {
List<Opportunity> visible = [
SELECT Id FROM Opportunity WHERE Id = :opp.Id
];
System.assertEquals(1, visible.size(), 'Sales user should read Opportunity');
}
}
The test exercises the profile's object permission and sharing. A failing test reveals the permission gap before users hit it in production.
For UI-level tests, use Lightning Testing or Playwright running as a non-admin user. Test that the page renders without the Insufficient Privileges fallback.
Diagnosing in production
When a user reports the page-level message:
- Capture the URL they clicked. Confirm which record and which object.
- Open the record yourself as an admin to confirm the record exists.
- Check the user's profile. Does it grant Read on the object?
- Check the user's permission sets. Do any grant access?
- Check sharing. As the user (via Login As), query the record. If the query returns nothing, sharing is the issue.
- Check restriction rules. As an admin, open the object's Restriction Rules and run the Preview.
- Check the record type. Is the user assigned to it?
- Apply the appropriate fix and have the user retry.
Logging in as the user (Setup → Users → user → Login) reproduces the exact view they see, which makes the layer faster to identify.
Defensive habits
Document permission changes in a change-control system. The week-of-change is the highest-risk window for Insufficient Privileges incidents. A record of "what changed when" lets you trace incidents back to the cause quickly.
Prefer permission sets over profiles. Profiles are blunt instruments. Permission sets compose, are easy to test, and are easy to revoke.
Run user-acceptance tests as a non-admin user. Many incidents come from features that work for the developer (who has admin) but fail for the actual user.
Audit the role hierarchy quarterly. Roles drift over time; new roles get added, old ones get retired, sharing-rule visibility through the hierarchy shifts.
Audit restriction rules monthly. A misconfigured restriction rule can lock thousands of users out of records they should see. Restriction rules are powerful and need careful testing.
Quick recovery checklist
- Identify the user and the record.
- Login as the user to reproduce.
- Walk through the layers: profile, permission sets, sharing, role hierarchy, restriction rules, record type.
- Find the failing layer.
- Apply the targeted fix: permission set, sharing rule, role move, restriction rule edit.
- Confirm with the user.
Most page-level Insufficient Privileges incidents resolve in 20-30 minutes once the cause layer is found. The longer incidents involve compound failures across multiple layers and benefit from a clean rebuild of the user's effective permissions.
Further reading from Salesforce
- Salesforce Help: Profiles and Permission Sets
- Salesforce Help: Restriction Rules
- Salesforce Help: Sharing Settings
- Architect: User Access and Permissions
- Trailhead: Data Security
Related dictionary terms
Share this fix
Related Security errors
ENTITY_FAILED_IFLASTMODIFIED_ON_UPDATE_CHECK: record has been modified since you retrieved it
SecurityYou sent an update with an `If-Unmodified-Since` header (or the API equivalent), and the record was modified by someone else after your read…
INSUFFICIENT_ACCESS_OR_READONLY: insufficient access rights on cross-reference id
SecurityThe running user can see the record they're trying to update, but doesn't have edit access to it (or to a record it depends on). The error m…
INVALID_CROSS_REFERENCE_KEY: invalid cross reference id
SecurityYou set a relationship field to an Id that the platform rejects — either the Id doesn't exist, points at the wrong object type, has been del…
invalid_grant: <reason>
SecuritySalesforce rejected the OAuth credentials in your token request. The `error_description` field tells you which part — refresh token revoked/…
invalid_grant: invalid_grant - challenge required / TWO_FACTOR_REQUIRED
SecuritySalesforce required Multi-Factor Authentication for the login but the integration didn't supply it. Most common with Username-Password OAuth…