Record Access Troubleshooting
Activate when a user reports "I can't see this record" or "Why can this user edit this record?" Troubleshooting record access means tracing the sharing chain: OWD → role hierarchy → ownership → sharing rules → teams → manual shares → Apex shares → implicit parent share. This skill gives a deterministic diagnostic flow using UserRecordAccess SOQL and the "Sharing" access debug tool, not guesswork.
Before Starting
- Gather specifics. User Id, Record Id, expected access (view/edit/delete), object OWD.
- Identify the object's OWD. Setup → Sharing Settings. Private / Public Read Only / Public Read/Write / Controlled by Parent.
- Check profile/permset modify-all. "Modify All Data" and "View All Data" bypass sharing entirely.
Core Concepts
UserRecordAccess (primary diagnostic)
SELECT RecordId, HasReadAccess, HasEditAccess, HasDeleteAccess,
HasTransferAccess, HasAllAccess, MaxAccessLevel
FROM UserRecordAccess
WHERE UserId = '005...' AND RecordId = '001...'
Returns the effective access result but not the reason. Run this first.
Explain Access button
On any record's Sharing detail page: "Why can this user access this record?" — lists the reason (Owner, Role Hierarchy, Sharing Rule X, Manual Share, Apex Managed Share, Implicit Parent). Available in Classic UI; Lightning has "Sharing Hierarchy."
Sharing reason chain (order Salesforce evaluates)
- Admin bypass. "View All Data" / "Modify All Data" / "View All" / "Modify All" on an object.
- Ownership. The record owner has full access (unless the role says otherwise).
- Role hierarchy. If enabled on the object, users above the owner's role inherit access.
- Sharing rules. Ownership- and criteria-based rules grant read or read/write.
- Teams. Account, Opportunity, Case teams.
- Manual shares. UI "Share" button.
- Apex managed shares.
__Sharerows with RowCause. - Implicit parent share. Child records on master-detail inherit parent access.
- Restriction rules. Filter DOWN access — user might have access via the above but restriction rule denies.
__Share objects
For every object with non-Public OWD, there's a <Object>__Share sharing table. Query it to see grants:
SELECT UserOrGroupId, AccessLevel, RowCause FROM Account__Share WHERE ParentId = '001...'
RowCause: Owner, Manual, Rule, Team, Implicit, , etc.
Restriction Rules
New-style restrictive filter on top of OWD. A user might have share access but see 0 rows because a restriction rule filters the query.
Common Patterns
Pattern: Minimal diagnostic query
SELECT RecordId, HasReadAccess, HasEditAccess, MaxAccessLevel
FROM UserRecordAccess
WHERE UserId = :uid AND RecordId = :rid
MaxAccessLevel returns "None", "Read", "Edit", "All".
Pattern: Trace via __Share table
SELECT Id, UserOrGroupId, AccessLevel, RowCause, ParentId
FROM Account__Share
WHERE ParentId = :rid
ORDER BY RowCause
Join against Group / User to resolve the grantee.
Pattern: Admin bypass check
SELECT PermissionsViewAllData, PermissionsModifyAllData
FROM PermissionSetAssignment
WHERE AssigneeId = :uid
If either is true, sharing is moot — explain the finding.
Decision Guidance
| Symptom | Likely cause |
|---|---|
| User sees record they shouldn't | View All Data perm / sharing rule / role hierarchy |
| User can't see record they should | OWD Private + no sharing rule match |
| Sharing rule configured but no effect | Rule targets criteria user's records don't match |
| Lost access after ownership change | Manual shares cleared on transfer (not Apex shares with RowCause) |
| Child record inaccessible | Master-detail parent not shared (implicit parent) |
| Recent access removed | Restriction rule introduced |
Recommended Workflow
- Query
UserRecordAccessfor the user/record pair. Confirms current state. - If access is unexpected, check profile/permset for View/Modify All.
- Open the record's Sharing detail → "Why can this user access?" — get the explicit reason.
- Query
__Sharefiltered by ParentId — enumerate all grants. - Check role hierarchy:
UserRoleof owner vs accessor. - Check for restriction rules on the object.
- Document root cause and remediation (add sharing rule / remove permission / adjust OWD).
Review Checklist
-
UserRecordAccessquery run first to confirm state - Admin-bypass permissions ruled in/out
-
__ShareRowCause chain enumerated - Role hierarchy relationship checked
- Restriction rules checked for the object
- Implicit-parent-share considered for child objects
- Remediation aligns with
sharing-selectiondecision tree
Salesforce-Specific Gotchas
- Manual shares disappear on ownership change. Re-create as Apex managed share with a RowCause (survives transfer).
- "Grant Access Using Hierarchies" is per-object and defaults on. Turning off for custom objects with Private OWD blocks role-based visibility.
UserRecordAccessrequires the query user to haveView All DataOR be the target user. Running as a sandbox admin works; running as a normal user impersonating will fail.- Restriction Rules apply AFTER sharing is computed — user may have a
__Sharerow yet still see zero results.
Output Artifacts
| Artifact | Description |
|---|---|
| UserRecordAccess diagnostic query | Drop-in SOQL for user/record pair |
| __Share trace query | Enumerates grant rows and causes |
| Sharing-chain narrative | Step-by-step reason write-up |
| Remediation recommendation | Cite sharing-selection branch |
Related Skills
security/sharing-rules-patterns— designing new sharing rulessecurity/apex-managed-sharing—__Shareinserts with RowCausesecurity/restriction-rules-patterns— filter-down accessstandards/decision-trees/sharing-selection.md— overall sharing technology selection