spring-projects/spring-ai · error · UnsupportedOperationException

Expression type {0} not supported for numeric fields

Error message

Expression type {0} not supported for numeric fields

What it means

RedisFilterExpressionConverter.numeric() only supports the comparison operators EQ, GT, GTE, LT and LTE when translating a Filter.Expression into a Redis numeric range. Any other expression type (e.g. NIN, AND, OR, IN applied to a numeric field) hits the default branch and throws this UnsupportedOperationException. It signals that the filter expression uses an operator the Redis numeric-range mapping cannot express.

Source

Thrown at vector-stores/spring-ai-redis-store/src/main/java/org/springframework/ai/vectorstore/redis/RedisFilterExpressionConverter.java:197

	}

	private String tagValueDelimiter(Expression expression) {
		return switch (expression.type()) {
			case IN -> " | ";
			case EQ -> " ";
			default -> throw new UnsupportedOperationException(
					MessageFormat.format("Tag operand {0} not supported", expression.type()));
		};
	}

	private Numeric numeric(Expression expression, Value value) {
		return switch (expression.type()) {
			case EQ -> new Numeric(inclusive(value), inclusive(value));
			case GT -> new Numeric(exclusive(value), NumericBoundary.POSITIVE_INFINITY);
			case GTE -> new Numeric(inclusive(value), NumericBoundary.POSITIVE_INFINITY);
			case LT -> new Numeric(NumericBoundary.NEGATIVE_INFINITY, exclusive(value));
			case LTE -> new Numeric(NumericBoundary.NEGATIVE_INFINITY, inclusive(value));
			default -> throw new UnsupportedOperationException(
					MessageFormat.format("Expression type {0} not supported for numeric fields", expression.type()));
		};
	}

	private NumericBoundary inclusive(Value value) {
		if (!(value.value() instanceof Number)) {
			throw new IllegalArgumentException("Numeric value must be a Number");
		}
		return new NumericBoundary(value.value(), false);
	}

	private NumericBoundary exclusive(Value value) {
		if (!(value.value() instanceof Number)) {
			throw new IllegalArgumentException("Numeric value must be a Number");
		}
		return new NumericBoundary(value.value(), true);
	}

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Use only supported operators (EQ, GT, GTE, LT, LTE) for numeric fields in your filter expression
  2. Express the negation differently, e.g. combine GT and LT ranges instead of NE/NIN
  3. If you control the code, extend RedisFilterExpressionConverter to map the missing expression type to an equivalent Redis range or tag set

Example fix

// before
Filter.Expression expr = new FilterExpressionBuilder().nin("year", 2020, 2021).build();
// after
Filter.Expression expr = new FilterExpressionBuilder().and(
    new FilterExpressionBuilder().lt("year", 2020).build(),
    new FilterExpressionBuilder().gt("year", 2021).build());
Defensive patterns

Strategy: validation

Validate before calling

java.util.Set<Filter.ExpressionType> SUPPORTED = Set.of(Filter.ExpressionType.EQ, Filter.ExpressionType.GT, Filter.ExpressionType.GTE, Filter.ExpressionType.LT, Filter.ExpressionType.LTE);
if (!SUPPORTED.contains(expr.type())) throw new IllegalArgumentException("Unsupported numeric operator: " + expr.type());

Try / catch

try { store.similaritySearch(req); } catch (UnsupportedOperationException e) { log.warn("Filter operator not supported for numeric fields", e); }

Prevention

When it happens

Trigger: Calling RedisVectorStore.similaritySearch() with a FilterExpressionBuilder expression whose type is not one of EQ/GT/GTE/LT/LTE on a numeric metadata field, e.g. a NIN or NE expression, or a top-level boolean expression passed where numeric() is invoked.

Common situations: Building filters with FilterExpressionBuilder.ne() or .nin() on a numeric field like 'year' or 'price'; porting filters written for another vector store that supports more operators; framework upgrades where new expression types appear but the converter was not extended.

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


AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11). Data as JSON: /api/errors/8737bc5f2931254b. Report an issue: GitHub.