In Salesforce, if a with sharing Apex class runs a SOQL query within the same transaction where a criteria-based sharing rule should share rows with the running user, the query will not return those rows.
This is because criteria-based sharing rules are evaluated at the end of Apex execution. The sharing entries are written to the database during the commit phase — which occurs after all Apex code for the request has finished.
Therefore, a SOQL query executed during the Apex transaction cannot access rows whose sharing has not yet been committed.
Per the Salesforce Order of Execution, criteria-based sharing rules are evaluated at the end of the execution flow. The shares created in memory during this evaluation are saved to the database during the commit phase — after all Apex execution for the request has finished.
Because the Apex transaction completes before the commit phase, any SOQL query run within the transaction cannot see rows shared via a criteria-based sharing rule that was also evaluated within the same transaction.
with sharing to without sharing, allowing the query to bypass sharing rule restrictions (use with caution — evaluate security implications first).
To reproduce this behavior in a test environment: Create an Apex controller with with sharing that inserts an Account record and then immediately queries it. Add a before-insert trigger that changes the OwnerId to a specific user (e.g., a user with the CEO role). Create a criteria-based sharing rule that shares accounts of a specific record type with users in roles below CEO.
When a user with a role below CEO runs the page and clicks the button to create the account, the SOQL query returns no results — "Could not query account" is displayed. This is because the sharing rule has not yet been committed at the time of the query. However, the same user can navigate directly to the Account record URL and view it successfully after the transaction completes.
Create the following Apex controller, Visualforce page, and Apex trigger.
public with sharing class AccountQueryIssue {
public String debugString { get; set; }
private Account a, b;
public AccountQueryIssue() {
debugString = '';
}
public void createAccount() {
// Replace record type ID with ID of an account record type
a = new Account(Name = 'Acme '+ System.now(), recordTypeId='012410000002S6O');
insert a;
debugString += '<br/>Inserted account:<br/>' + JSON.serialize(a) + '<br/>';
try {
b = [SELECT Id, Name, Owner.Alias FROM Account where id = :a.Id];
} catch(Exception e) { }
if(b != null)
debugString += '<br/>Queried account:<br/>' + JSON.serialize(b) + '<br/>';
else
debugString += '<br/>Could not query account<br/>';
}
}
VF Page
<apex:page controller="AccountQueryIssue" showHeader="false" sidebar="false">
<apex:form >
<apex:commandButton action="{!createAccount}" value="Create Account"/>
</apex:form>
<apex:outputText escape="false" value="{!debugString}"/>
</apex:page>
Apex Trigger
trigger ChangeOwner on Account (before insert) {
for(Account a : Trigger.new) {
// Replace OwnerId with ID of user with role CEO
a.OwnerId = '00541000000HJYT';
}
}
000382331

We use three kinds of cookies on our websites: required, functional, and advertising. You can choose whether functional and advertising cookies apply. Click on the different cookie categories to find out more about each category and to change the default settings.
Privacy Statement
Required cookies are necessary for basic website functionality. Some examples include: session cookies needed to transmit the website, authentication cookies, and security cookies.
Functional cookies enhance functions, performance, and services on the website. Some examples include: cookies used to analyze site traffic, cookies used for market research, and cookies used to display advertising that is not directed to a particular individual.
Advertising cookies track activity across websites in order to understand a viewer’s interests, and direct them specific marketing. Some examples include: cookies used for remarketing, or interest-based advertising.