spring-projects/spring-ai · error · RuntimeException

Unsupported value type for LT condition. Only supports Numbe

Error message

Unsupported value type for LT condition. Only supports Number

What it means

Raised while converting a parsed '<field> LT <value>' expression into a Qdrant range condition: Qdrant's Range filter only supports numeric comparisons, but the filter value given for the LT operator was not a Number (e.g. a string or boolean). The converter cannot express a less-than comparison over a non-numeric value in Qdrant, so it aborts. The fault lies in the caller's filter expression — use EQ/NE for non-numeric comparisons or supply a numeric value.

Source

Thrown at vector-stores/spring-ai-qdrant-store/src/main/java/org/springframework/ai/vectorstore/qdrant/QdrantFilterExpressionConverter.java:139

	}

	protected Condition buildGtCondition(Key key, Value value) {
		String identifier = doKey(key);
		if (value.value() instanceof Number valueNum) {
			Double dvalue = Double.parseDouble(valueNum.toString());
			return io.qdrant.client.ConditionFactory.range(identifier, Range.newBuilder().setGt(dvalue).build());
		}
		throw new RuntimeException("Unsupported value type for GT condition. Only supports Number");

	}

	protected Condition buildLtCondition(Key key, Value value) {
		String identifier = doKey(key);
		if (value.value() instanceof Number valueNum) {
			Double dvalue = Double.parseDouble(valueNum.toString());
			return io.qdrant.client.ConditionFactory.range(identifier, Range.newBuilder().setLt(dvalue).build());
		}
		throw new RuntimeException("Unsupported value type for LT condition. Only supports Number");

	}

	protected Condition buildGteCondition(Key key, Value value) {
		String identifier = doKey(key);
		if (value.value() instanceof Number valueNum) {
			Double dvalue = Double.parseDouble(valueNum.toString());
			return io.qdrant.client.ConditionFactory.range(identifier, Range.newBuilder().setGte(dvalue).build());
		}
		throw new RuntimeException("Unsupported value type for GTE condition. Only supports Number");

	}

	protected Condition buildLteCondition(Key key, Value value) {
		String identifier = doKey(key);
		if (value.value() instanceof Number valueNum) {
			Double dvalue = Double.parseDouble(valueNum.toString());
			return io.qdrant.client.ConditionFactory.range(identifier, Range.newBuilder().setLte(dvalue).build());

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Use a numeric value for the LT comparison

Example fix

// before
Filter.builder().lt("price", request.getMaxPrice()) // String "9.99"
// after
Filter.builder().lt("price", Double.parseDouble(request.getMaxPrice())).build();
Defensive patterns

Strategy: validation

Validate before calling

static void checkLtOperand(Object v) {
    if (!(v instanceof Number)) {
        throw new IllegalArgumentException("LT operand must be a Number, got " + (v == null ? "null" : v.getClass()));
    }
}

Type guard

static boolean isNumber(Object v) {
    return v instanceof Number;
}

Try / catch

try {
    vectorStore.similaritySearch(req);
} catch (RuntimeException ex) {
    if (ex.getMessage() != null && ex.getMessage().contains("LT condition. Only supports Number")) {
        throw new IllegalArgumentException("LT requires a numeric operand", ex);
    }
    throw ex;
}

Prevention

When it happens

Trigger: Filter.builder().lt("price", "9.99").build() — a numeric value supplied as a String, or any Boolean/date operand.

Common situations: Numbers deserialized from JSON/config as strings (e.g. reading query params as String and passing them straight into the filter).

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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