System.QueryException: Only variable references are allowed in dynamic SOQL/SOSL
What does this error mean?
In dynamic SOQL (queries built as strings and run with Database.query()), bind variable syntax — using : before a name — must reference an Apex variable that exists in the current scope. You cannot use a literal value like :'someString' or :0050W000007Jz7jQAC directly in the query string. Salesforce evaluates the bind expression against the Apex runtime scope, not the string content.
Common Causes
1. Hardcoded ID literal in bind position
Writing WHERE OwnerId =: 0050W000007Jz7jQAC inside a dynamic query string. The colon-prefixed value must be a variable name, not a literal ID.
2. String literal in bind position
Something like 'WHERE Status__c =: \'Active\'' — the value after : must be an Apex variable identifier.
3. Confusion between static and dynamic SOQL syntax
Static SOQL (inline brackets) evaluates bind variables at parse time and can reference any in-scope variable. Dynamic SOQL uses the same syntax but evaluates at runtime — the variable must be in scope when Database.query() is called.
How to Fix It
Solution 1: Assign the value to a variable first
Always assign any value you want to bind to a named Apex variable before including it in the query string.
// ❌ BAD — literal ID in bind position
String soql = 'SELECT Id FROM User WHERE Id =: 0050W000007Jz7jQAC';
// ✅ GOOD — variable in scope
Id targetId = '0050W000007Jz7jQAC';
String soql = 'SELECT Id FROM User WHERE Id = :targetId';
List<User> results = Database.query(soql);
// ✅ Also works — string literal in variable
String statusFilter = 'Active';
String soql2 = 'SELECT Id FROM Account WHERE Status__c = :statusFilter';
Solution 2: Use string interpolation for non-sensitive values
For values that don't come from user input, you can safely interpolate them directly into the query string using String.escapeSingleQuotes() to prevent SOQL injection.
// ✅ Safe interpolation for trusted internal values
String safeStatus = String.escapeSingleQuotes('Active');
String soql = 'SELECT Id FROM Account WHERE Status__c = \' + safeStatus + '\';
// ⚠️ NEVER interpolate user-provided input without escaping
// Use bind variables (:varName) for user input — always
Security note: Always use bind variable syntax (:variableName) for any value derived from user input. Never concatenate user-provided values into SOQL strings — this opens a SOQL injection vulnerability. Only use string interpolation for values you fully control.