Row Causes, Access Levels and Sharing Reasons
Module 2 of 6 in the chapter Programmatic Sharing: Apex and Flow Managed Sharing, chapter 11 of Securing Salesforce: Sharing and Visibility. Each module stands on its own.
The question this module answers: What does a share table really hold, and why does one share survive an owner change when another doesn’t?
Chapter 5 gave the four pieces of a share record: which record, who, how much and why (Set 5, Programmatic). This module opens the table itself. Because if your code writes rows into it, you need to know what’s already there, what isn’t, and what Salesforce will do to your rows later.
The share table, and what isn’t in it
Section titled “The share table, and what isn’t in it”Every object that can be shared has a share table beside it, and its name ends in Share: AccountShare, or Apple__Share for a custom object called Apple. I call it a shadow image of the main table. Salesforce calls it something close: “Most sharing for a record is maintained in a related sharing object, similar to an access control list (ACL) found in other platforms” (Understanding Sharing (opens in a new tab), Apex Developer Guide, Winter ‘27, checked 2026-11-07).
Notice the word “most.” The share table holds many of the shares, but not all of them. You cannot assume all sharing is in the share table. Three things you won’t find there:
- The role hierarchy. “The role hierarchy is not maintained with sharing records. Instead, role hierarchy access is derived at runtime” (Understanding Sharing).
- The overrides. View All and Modify All, and the All Data permissions, aren’t rows. They’re permissions (chapter 10, module 1).
- Child implicit access to an account’s cases, contacts and opportunities. Salesforce stopped storing it and works it out when the record is opened (chapter 10, module 4).
So when you query a share table to answer “why can this person see this record?”, you get part of the answer. The rest comes from the hierarchy and the permissions.
The row cause: why the row exists
Section titled “The row cause: why the row exists”Every row has a row cause. The row cause is the reason the sharing exists. In the user interface it’s the Reason column when you look at a record’s sharing; in Apex and the API it’s RowCause. Salesforce lists the values (Understanding Sharing):
| Who writes it | Reason shown | RowCause |
|---|---|---|
| Salesforce | Owner | Owner |
| Salesforce | Sharing Rule | Rule |
| Salesforce | Opportunity Team | Team |
| Salesforce | Territory Assignment Rule | TerritoryRule |
| Salesforce | Account Sharing | ImplicitChild |
| Salesforce | Associated record owner or sharing | ImplicitParent |
| A person (or code) | Manual Sharing | Manual |
| A person (or code) | Territory Manual | TerritoryManual (Territory2AssociationManual with Enterprise Territory Management, API version 45.0 and later) |
| Your code | Defined by you | Your own, ending in __c |
Read the first column. The Salesforce rows are Salesforce’s. “All implicit sharing added by Force.com managed sharing cannot be altered directly using the Salesforce user interface, SOAP API, or Apex” (Understanding Sharing). Your code can’t delete a rule’s row or an owner’s row. It can write two kinds: Manual, and a reason of its own.
And that choice, Manual or your own, decides what happens to your row later.
Watch it go: the green apple
Section titled “Watch it go: the green apple”Here’s how I show it in class. I build a custom object called Apple, set it to Private, and create one record, a green apple. A standard user with access to the object sees no apples at all. Prove the negative first.
Then I insert a share from code: the green apple, that user, Read, with the row cause Manual. The user refreshes, and there’s the green apple. The query on Apple__Share shows two rows: the owner’s, and mine.
Now the question for the room. I change the green apple’s owner to a second user. What happens to the share my code wrote?
It’s gone. Salesforce treats a Manual row like a manual share made by a person, and “User managed sharing is removed when the record owner changes” (Understanding Sharing). Winter ‘27 added an org setting to keep manual shares when records are transferred (Manual Sharing, chapter 9). Don’t build code on it: Salesforce’s own advice for shares written by code is a reason of your own (module 3).
So how do you make it stick? You need a sharing reason of your own. I go to the Apple object, look for sharing reasons, and they aren’t there. That’s the trick: you have to go to Salesforce Classic. There, the object has an Apex Sharing Reasons list, and I create one. What’s a reason to share an apple? A party. So the reason is called Party.
Back in Lightning, I insert the same share, with the row cause Party. Change the owner again, and this time the user keeps the green apple. “Apex managed sharing is maintained when the record owner changes or is deactivated” (Understanding Sharing).
Test knowledge. Know that a share written by code with the Manual row cause is removed when the owner changes, and that a share with an Apex sharing reason is kept when the owner changes or is deactivated. Know that only users with Modify All Data can add or change Apex managed sharing, and that “You can’t use Apex to create criteria-based sharing rules. Also, criteria-based sharing cannot be tested using Apex” (Understanding Sharing). A likely area, not a known question.
The sharing reason itself
Section titled “The sharing reason itself”A sharing reason has two parts (Sharing a Record Using Apex (opens in a new tab), Apex Developer Guide, Winter ‘27, checked 2026-11-07):
- The label “displays in the Reason column when viewing the sharing for a record in the user interface.” That’s how an admin, years later, finds out why someone has access. And it “is also enabled for translation through the Translation Workbench.” So name it for the people who’ll read it, in every language your org runs in.
- The name is what your code uses. It ends in
__c, so Party becomesParty__c, and your code refers to it asSchema.Apple__Share.RowCause.Party__c.
Where do you create it? For a custom object, still in Classic: “Apex sharing reasons aren’t available in Lightning Experience. Use Salesforce Classic to create sharing reasons within the UI” (same page). For standard objects, it’s the Metadata API or Tooling API, and that’s new enough to have its own module (module 3).
Two conditions before a reason is available at all: the object needs a share object, and its default has to be Private or Public Read Only (same page). On Public Read/Write there’s nothing left to share.
And you can have more than one. Reasons “enable developers to share with the same user or group multiple times using different reasons,” and they make updates and deletions simpler (same page). That’s the real design choice: one reason for each rule your code applies. Recruiter and Hiring Manager, in Salesforce’s own example. Then, when the recruiter changes, your code removes only the Recruiter rows, and the Hiring Manager’s rows don’t move.
Access levels, and which one wins
Section titled “Access levels, and which one wins”Most share objects take these levels (Understanding Sharing):
- None: “This access level only applies to the AccountShare object.” On AccountShare it’s how a row says no access to the account’s cases or opportunities.
- Read: view only.
- Edit: view and edit.
- All: view, edit, transfer, share and delete. “This access level can only be granted with managed sharing.” Your code can’t give it. Full access stays with the owner and the hierarchy above them.
Two rules decide what the user actually gets:
- The most permissive wins. “When determining a user’s access to a record, the most permissive level of access is used” (Understanding Sharing). A rule gives Read and your code gives Edit: the user can edit. Remove your row, and they’re back to Read.
- A share has to add something. A share at or below the object’s default isn’t needed, and Salesforce’s own example code expects the insert to fail with an error about a “trivial access level” and lets it go, because “These sharing records are not required” (Sharing a Record Using Apex). The object’s default also “must not be set to the most permissive access level.”
And sometimes your insert doesn’t add a row at all. “Under certain circumstances, inserting a share row results in an update of an existing share row”: a manual share at Read, then a new one at Edit, leaves one row at Edit. And a user who sees an account through its child, then gets an account sharing rule, has the rule’s row cause replace the parent implicit one (same page). So don’t count rows to test your code. Query what each user can do.
Watch it on video
Section titled “Watch it on video”In 2023 I made a video that writes shares by hand with a few lines of Apex and a sharing reason of my own, and watches the user’s records go up one at a time. The note under the video says what’s still right and what’s changed since.
What an architect decides here
Section titled “What an architect decides here”- For every share code writes: Manual or a reason of your own, decided by what must happen when the owner changes.
- One reason per rule in the code, named so the Reason column explains itself, and translated where the org needs it.
- Which objects can use reasons at all: a share object, and a default of Private or Public Read Only.
- What an access review reads: the share table, plus the role hierarchy and the overrides, which aren’t in it.
- How the code is tested: by what each user can see and do, not by how many rows exist.
Beyond the exam: what AI changes. When you ask “why can this agent’s user see this record?”, an AI assistant will often query the share table and stop there. Teach it the rest of the answer: the role hierarchy, View All and Modify All, and the child implicit access that isn’t stored. And when an assistant writes sharing code for you, check its row cause first. If it wrote Manual, ask whether those shares should vanish the next time an owner changes. Chapter 20 covers agents.
Explore
Section titled “Explore”- Understanding Sharing (opens in a new tab), Apex Developer Guide, Winter ‘27 (checked 2026-11-07)
- Sharing a Record Using Apex (opens in a new tab), Apex Developer Guide, Winter ‘27 (checked 2026-11-07)
