INVALID_SEARCH: search term must be longer than one character
A SOSL `FIND` expression had a search term shorter than two characters, or used wildcards in a way the parser rejects. SOSL has stricter rules than regular full-text search engines — single-letter searches and leading wildcards are blocked.
Also seen asINVALID_SEARCH·search term must be longer than one character·SOSL search must include identifier·search query too short
SOSL is the platform's text-search language, separate from SOQL. The FIND clause is parsed differently from a SQL WHERE, and its quirks confuse people coming from Elasticsearch or Postgres FTS.
The rules
- Search terms must be at least 2 characters.
FIND {a}throws;FIND {ab}works. - Leading wildcards are rejected.
FIND {*foo}is invalid (would force a full index scan). Trailing and middle wildcards are fine:FIND {foo*}andFIND {f*o}. - Unquoted reserved words confuse the parser.
FIND {AND}doesn't search for the word "AND" — it's a syntax error. Quote the term:FIND {"AND"}. - Stopwords (the, and, or, of, etc.) are ignored by the index. A
FIND {the}returns nothing because the indexer dropped it. - Each search term gets a minimum of 2 characters AFTER stopword removal. So
FIND {a or b}is effectivelyFIND {b}(a is below 2-char minimum, "or" is a stopword) — and that single-letter is then below the threshold.
The shape of a valid SOSL query
FIND {Acme*} IN Name FIELDS RETURNING Account(Id, Name), Contact(Id, Email)
Acme* matches any word starting with Acme. Returns Accounts (Id, Name) and Contacts (Id, Email) where the term hits any indexed Name field.
In Apex:
List<List<SObject>> hits = [FIND :userInput IN ALL FIELDS RETURNING Account(Id, Name)];
List<Account> matched = (List<Account>) hits[0];
The bind variable userInput is escaped automatically. Don't string-concat user input into FIND — same SOSL-injection risk as SOQL.
Apex-side validation
Validate the user's search term before issuing the query. Salesforce's tolerance for "too short" is wider than yours should be:
String term = userInput.trim();
if (term.length() < 2 || isAllStopwords(term)) {
return new List<Account>(); // or show a friendly "type more" hint
}
String escaped = String.escapeSingleQuotes(term);
List<List<SObject>> hits = [FIND :escaped IN ALL FIELDS RETURNING Account(Id, Name)];
String.escapeSingleQuotes handles SOSL's quoting rules. For wildcards, build them server-side:
String pattern = escaped + '*'; // user typed "ac"; we look for "ac*"
Don't let the user type their own wildcards — they'll forget the leading-wildcard rule and you'll handle every error case yourself.
Why these rules exist
SOSL hits a separate full-text index (SearchVector columns on every searchable object) that's optimised for fast lookup with bounded queries. Allowing single-character or leading-wildcard searches would force the engine to scan everything, breaking SLA. The platform draws a clean line: minimum 2 characters, no leading wildcards, period.
When you really need a single-character search
Use SOQL LIKE instead. SOQL's LIKE doesn't have the same restrictions — WHERE Name LIKE 'A%' is valid. The tradeoff: SOQL is per-object (you have to query each table separately and union the results), whereas SOSL is cross-object in one query. For a global "search everywhere" feature, SOSL is right; for "find one specific record by partial match," SOQL LIKE is fine.
