spring-projects/spring-ai · error · IllegalArgumentException
Not allowed filter identifier name:
Error message
Not allowed filter identifier name:
What it means
Typesense filter_by field names are bare identifiers (field_name:value) with no escaping mechanism, so doKey validates that the metadata key contains only letters, digits, '_', '.', and '-'. Any other character (spaces, quotes, parentheses, etc.) triggers this IllegalArgumentException, which also prevents filter injection through crafted key names.
Solutions
- Rename the metadata key in your documents to use only letters, digits, '_', '.', '-' (e.g. 'user_name').
- Sanitize/validate identifier strings before embedding them into Filter expressions (e.g. replace invalid characters).
- Validate user-supplied field names against a whitelist before constructing filter expressions.
Example fix
// before
var expr = new Filter.Expression(EQ, new Key("user name"), new Value("alice"));
// after
var expr = new Filter.Expression(EQ, new Key("user_name"), new Value("alice")); Defensive patterns
Strategy: validation
Validate before calling
if (!key.matches("[A-Za-z0-9_.-]+")) throw new IllegalArgumentException("Illegal Typesense filter key: " + key); Try / catch
try { vectorStore.similaritySearch(req); } catch (IllegalArgumentException e) { if (e.getMessage().startsWith("Not allowed filter identifier")) { /* sanitize key and retry */ } else throw e; } Prevention
- Use only letters, digits, '_', '.', '-' in metadata keys for Typesense
- Sanitize user-supplied field names before building filters
- Standardize document metadata key naming (e.g. camelCase or snake_case) at ingestion time
When it happens
Trigger: Running a similaritySearch or delete-by-filter with a Key metadata identifier containing characters outside [A-Za-z0-9_.-], e.g. 'user name', 'price$usd', or a key containing ':' or '"'.
Common situations: Documents stored with metadata keys containing spaces or special characters; dynamically building keys from user input without sanitizing; migrating from stores that allowed arbitrary key names.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- Not allowed filter identifier name:
- Not allowed filter identifier name: . Consider adding it to…
- Not supported expression type:
- Cannot compare values of incompatible types
- Cannot compare values of incompatible types
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/78addaf1a039aae1.
Report an issue: GitHub.
Appendix: source
Thrown at vector-stores/spring-ai-typesense-store/src/main/java/org/springframework/ai/vectorstore/typesense/TypesenseFilterExpressionConverter.java:71
};
}
@Override
protected void doGroup(Filter.Group group, StringBuilder context) {
this.convertOperand(new Filter.Expression(Filter.ExpressionType.AND, group.content(), group.content()),
context); // trick
}
@Override
protected void doKey(Filter.Key key, StringBuilder context) {
var identifier = (hasOuterQuotes(key.key())) ? removeOuterQuotes(key.key()) : key.key();
// Typesense field names are bare identifiers in filter_by syntax
// (field_name:value) with no escaping mechanism. Validate that the
// identifier contains only safe characters to prevent filter injection.
for (int i = 0; i < identifier.length(); i++) {
char c = identifier.charAt(i);
if (!Character.isLetterOrDigit(c) && c != '_' && c != '.' && c != '-') {
throw new IllegalArgumentException("Not allowed filter identifier name: " + identifier);
}
}
context.append("metadata.").append(identifier).append(":");
}
/**
* Serialize values using JSON serialization for Typesense filter expressions.
* Delegates to {@link #emitJsonValue(Object, StringBuilder)} for Jackson-based JSON
* serialization.
* @param value the value to serialize
* @param context the context to append the JSON representation to
*/
@Override
protected void doSingleValue(Object value, StringBuilder context) {
emitJsonValue(value, context);
}
}View on GitHub (pinned to 98a7beda4f)