Known Issues
Variable does not exist
Error: System.QueryException: Variable does not exist: v1
Root Cause
This is NOT a SOQL Lib issue but rather a Salesforce platform limitation that occurs when Database.getQueryLocatorWithBinds
is used with insufficient field-level security permissions.
This error occurs when all of the following conditions are met:
toQueryLocator()
method is executed- Query is executed with
USER_MODE
(which is the default access level if not otherwise specified) - Query contains fields to which the current user lacks read access permissions
- Query includes at least one WHERE condition, resulting in a non-empty binding map
- The Salesforce platform fails to validate field access permissions before processing bound variables
Example that fails:
Native Apex
Database.getQueryLocatorWithBinds(
'SELECT Type FROM Task WHERE Type != :v1',
new Map<String, Object>{'v1' => null},
AccessLevel.USER_MODE
);
SOQL Lib
SOQL.of(Task.SObjectType)
.with(Task.Type) // <== User lacks read access to this field
.whereAre(SOQL.Filter.with(Task.Type).isNotNull())
.toQueryLocator();
Technical Context
The error occurs because Salesforce's Database.getQueryLocatorWithBinds
method attempts to validate bound variables before performing field-level security checks. When the user lacks access to fields referenced in the query, the platform cannot properly resolve the bound variables, resulting in the misleading "Variable does not exist" error message instead of a more accurate field access permission error.
Solutions
Option 1: Grant Field Access Permissions
Grant the current user appropriate field-level security permissions for all fields referenced in the query through:
- Profile Settings: Update the user's profile to include read access to the required fields
- Permission Sets: Assign permission sets that grant access to the necessary fields
- Field-Level Security: Configure field-level security settings for the specific fields
Option 2: Use SYSTEM_MODE
Execute the query with elevated permissions using SYSTEM_MODE
to bypass field-level security restrictions:
Native Apex
Database.getQueryLocatorWithBinds(
'SELECT Type FROM Task WHERE Type != :v1',
new Map<String, Object>{'v1' => null},
AccessLevel.SYSTEM_MODE
);
SOQL Lib
SOQL.of(Task.SObjectType)
.with(Task.Type)
.whereAre(SOQL.Filter.with(Task.Type).isNotNull())
.systemMode() // <== Bypasses field-level security
.toQueryLocator();
Security Consideration: Use SYSTEM_MODE
judiciously as it bypasses security controls and may expose sensitive data to unauthorized users.
Variable does not exist: SObjectType
Error: Error: Variable does not exist: SObjectType
Root Cause
This error occurs due to Apex variable name conflicts when a local variable name matches the SObjectType class name used in the SOQL query. Apex's compiler becomes confused between the local variable reference and the SObjectType static reference, leading to compilation errors.
Example that fails:
Contact contact = new Contact(FirstName = 'Test', LastName = 'Test');
List<Contact> contacts = SOQL.of(Contact.SObjectType) // <== Conflict with 'contact' variable
.with(Contact.Id, Contact.Name)
.setLimit(10)
.toList();
Technical Context
In Apex, when you declare a variable with the same name as an SObjectType (e.g., Contact contact
), the compiler prioritizes the local variable scope over the static class reference. This causes Contact.SObjectType
to be interpreted as attempting to access a property on the local contact
variable rather than the static Contact
class, resulting in the compilation error.
Solution
Use Distinct Variable Names
Ensure local variable names are distinct from SObjectType class names to avoid namespace conflicts:
Example that works:
Contact contactRecord = new Contact(FirstName = 'Test', LastName = 'Test');
List<Contact> contacts = SOQL.of(Contact.SObjectType)
.with(Contact.Id, Contact.Name)
.setLimit(10)
.toList();
Method does not exist or incorrect signature: void of(Schema.SObjectField)
Error: Error: Method does not exist or incorrect signature: void of(Schema.SObjectField) from the type SOQL
Root Cause
This error occurs due to Salesforce's incomplete SObjectType implementation for certain system objects. The issue stems from Salesforce's internal architecture where certain objects are treated as "pseudo-SObjects" that don't fully implement the standard SObject interface, leading to missing or incomplete method signatures.
Technical Context
Primary Object Affected:
- RecordType
Example that fails:
SOQL.of(RecordType.SObjectType)
.setLimit(1)
.toObject();
Solution
Use String API Name Instead of SObjectType
Use SOQL.of('RecordType')
with the string API name instead of using the SObjectType reference.
Example that works:
SOQL.of('RecordType')
.setLimit(1)
.toObject();