spring-projects/spring-ai · error · RuntimeException
Unsupported expression type:
Error message
Unsupported expression type:
What it means
parseComparison switches on the Filter.Expression's ExpressionType and maps EQ, NE, GT, GTE, LT, LTE, IN and NIN to Qdrant conditions. Any other type reaching a comparison (because the message says "Unsupported expression type: " without even appending the type) throws a RuntimeException. It indicates an expression type that Qdrant translation does not implement.
Source
Thrown at vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantFilterExpressionConverter.java:88
}
return context.addAllMust(mustClauses).addAllShould(shouldClauses).addAllMustNot(mustNotClauses).build();
}
protected Condition parseComparison(Key key, Value value, Expression exp) {
ExpressionType type = exp.type();
return switch (type) {
case EQ -> buildEqCondition(key, value);
case NE -> buildNeCondition(key, value);
case GT -> buildGtCondition(key, value);
case GTE -> buildGteCondition(key, value);
case LT -> buildLtCondition(key, value);
case LTE -> buildLteCondition(key, value);
case IN -> buildInCondition(key, value);
case NIN -> buildNInCondition(key, value);
default -> throw new RuntimeException("Unsupported expression type: " + type);
};
}
protected Condition buildEqCondition(Key key, Value value) {
String identifier = doKey(key);
if (value.value() instanceof String valueStr) {
return io.qdrant.client.ConditionFactory.matchKeyword(identifier, valueStr);
}
else if (value.value() instanceof Number valueNum) {
long lValue = Long.parseLong(valueNum.toString());
return io.qdrant.client.ConditionFactory.match(identifier, lValue);
}
throw new IllegalArgumentException("Invalid value type for EQ. Can either be a string or Number");
}
protected Condition buildNeCondition(Key key, Value value) {View on GitHub (pinned to 98a7beda4f)
Solutions
- Restrict filter expressions to the supported set: EQ, NE, GT, GTE, LT, LTE, IN, NIN plus group operators AND/OR/NOT.
- Check the Qdrant converter version and upgrade spring-ai-qdrant-store so newer expression types are supported.
- Pre-process/reduce the expression (e.g. split unsupported combinators into multiple queries) before passing it to Qdrant.
- If you subclass QdrantFilterExpressionConverter, override parseComparison to handle your custom types.
Example fix
// before
Filter.builder().not(Filter.builder().eq("genre","drama").build()) // unsupported combinator in some paths
// after
Filter.builder().nin("genre", List.of("drama")).build(); Defensive patterns
Strategy: validation
Validate before calling
static final Set<ExpressionType> SUPPORTED = Set.of(EQ, NE, GT, GTE, LT, LTE, IN, NIN, AND, OR, NOT);
static void assertSupported(Filter.Expression e) {
if (!SUPPORTED.contains(e.type())) throw new IllegalArgumentException("Unsupported type " + e.type());
} Type guard
static boolean qdrantSupports(ExpressionType t) {
return t == ExpressionType.EQ || t == ExpressionType.NE || t == ExpressionType.GT || t == ExpressionType.GTE
|| t == ExpressionType.LT || t == ExpressionType.LTE || t == ExpressionType.IN || t == ExpressionType.NIN;
} Try / catch
try {
return vectorStore.similaritySearch(req);
} catch (RuntimeException ex) {
if (ex.getMessage() != null && ex.getMessage().startsWith("Unsupported expression type")) {
log.warn("Filter dropped, unsupported expression", ex);
return vectorStore.similaritySearch(reqWithoutFilter);
}
throw ex;
} Prevention
- Stick to the documented expression types for Qdrant.
- Upgrade spring-ai-qdrant-store when new ExpressionTypes appear upstream.
- Centralize filter construction in one utility so unsupported types are caught early.
When it happens
Trigger: Passing a filterExpression containing an unsupported ExpressionType to the Qdrant vector store — typically types that should have been handled by group logic (AND/OR/NOT) but reached parseComparison due to a converter bug, or exotic types from a custom ExpressionType enum.
Common situations: Rare in practice; usually seen when a shared filter-conversion utility passes group expressions straight into comparison parsing, or when new Spring AI ExpressionType values are added that the Qdrant converter has not been updated for.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Non AND/OR/NOT expression must have Value right argument!
- Invalid value type for EQ. Can either be a string or Number
- Invalid value type for NEQ. Can either be a string or Number
- Unsupported value type for GT condition. Only supports Numbe
- Unsupported value type for LT condition. Only supports Numbe
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/aebe158b05799a7f.
Report an issue: GitHub.