Salesforce Dictionary - Free Salesforce GlossarySalesforce Dictionary
All errors
SOQL

MALFORMED_QUERY: unexpected token

The SOQL parser couldn't make sense of your query. The error message tells you the exact word it choked on — that's where the syntax broke. Most often it's a quoting problem, an unsupported keyword, or a relationship name typo.

Also seen asMALFORMED_QUERY·unexpected token·MALFORMED_QUERY: unexpected token·INVALID_QUERY_LOCATOR malformed

SOQL looks like SQL but is much stricter. The parser reports the first unexpected token, and that's almost always either right where you wrote a typo or one token after the actual problem.

Read it like a stack trace

MALFORMED_QUERY:
  SELECT Id, Name FROM Account WHERE Name = 'O'Brien'
                                              ^
unexpected token: 'Brien'

The parser sees the closing quote, considers the string literal done at 'O', and now Brien' is just a stray identifier. The fix is escaping the apostrophe by doubling it: 'O''Brien'. In Apex code, you'd write the literal as 'O\'Brien' — backslash for the embedded source-level escape, and the bind variable handles the double-up for you automatically:

String name = 'O\'Brien';
List<Account> hits = [SELECT Id, Name FROM Account WHERE Name = :name];

Always prefer bind variables (:variable) over string concatenation. The platform escapes them correctly and they keep you safe from SOQL injection.

The other classic offenders

  • Reserved words used as identifiers. Field names like Group, User, or Date need to be qualified or quoted with the table alias.
  • Cross-object queries with a typo. Querying SELECT Account.Name FROM Contact works; SELECT Acccount.Name (extra c) gives you unexpected token: Acccount.
  • Child relationship name confusion. Subqueries use the relationship name, not the child object's API name:
    SELECT Id, (SELECT Id FROM Contacts) FROM Account     -- right (relationship 'Contacts')
    SELECT Id, (SELECT Id FROM Contact)  FROM Account     -- wrong (object name)
    
    Custom objects use __r for the relationship: SELECT Id, (SELECT Id FROM Cases__r) FROM Account__c.
  • Mixing single-row and aggregate selects. SELECT COUNT(Id), Id FROM Account doesn't work; aggregate queries can only mix non-aggregated fields if they're in GROUP BY.
  • LIKE with no wildcard. Allowed by the parser but probably not what you meant. The error usually shows up later as zero results.

Reproduce it cleanly

Don't debug SOQL inside an Apex method. Open Setup → Developer Console → Query Editor and paste the literal query string. The Query Editor's error messages are clearer and you can iterate fast. Once it parses, port it back to Apex and replace literals with bind variables.

When the parser is right but it feels wrong

If you're sure the query looks valid, two situations to suspect:

  • A field that doesn't exist on this profile / permission set (you'd actually get INVALID_FIELD for that, not MALFORMED_QUERY — see INVALID_FIELD: No such column).
  • A query string built by string concatenation where a variable resolved to the empty string. 'WHERE Status = \'' + maybeNull + '\'' becomes WHERE Status = '' with a stray quote. Bind variables avoid this.

Related dictionary terms