spring-projects/spring-ai · error · RuntimeException

Not supported expression type:

Error message

Not supported expression type: 

What it means

AzureAiSearchFilterExpressionConverter.getOperationSymbol translates Spring AI Filter.Expression types into Azure AI Search OData operator strings (lt, le, gt, ge, search.in). If the expression's type is not one of the six supported comparison types (e.g. AND, OR, NOT passed here unexpectedly), the default branch throws a RuntimeException naming the unsupported type. This is a defensive guard: group types should be routed elsewhere before reaching this switch.

Source

Thrown at vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverter.java:90

	}

	protected void doEndValueRange(Filter.Value listValue, StringBuilder context) {
		context.append("'");
	}

	private String getOperationSymbol(Expression exp) {
		return switch (exp.type()) {
			case AND -> " and ";
			case OR -> " or ";
			case EQ -> " eq ";
			case NE -> " ne ";
			case LT -> " lt ";
			case LTE -> " le ";
			case GT -> " gt ";
			case GTE -> " ge ";
			case IN -> " search.in";
			case NIN -> " not search.in";
			default -> throw new RuntimeException("Not supported expression type: " + exp.type());
		};
	}

	@Override
	public void doKey(Key key, StringBuilder context) {
		var hasOuterQuotes = hasOuterQuotes(key.key());
		var identifier = (hasOuterQuotes) ? removeOuterQuotes(key.key()) : key.key();
		var prefixedIdentifier = withMetaPrefix(identifier);
		if (hasOuterQuotes) {
			prefixedIdentifier = "'" + prefixedIdentifier.trim() + "'";
		}
		context.append(prefixedIdentifier);
	}

	/**
	 * Adds the metadata field prefix to the given identifier name. Azure AI Search
	 * requires metadata fields to be prefixed with "meta_" to distinguish them from
	 * system fields.

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Only pass comparison-type expressions (LT, LTE, GT, GTE, IN, NIN) to this converter; wrap AND/OR in Filter.and()/Filter.or() and let doExpression route them to doStartGroup/doEndGroup
  2. Upgrade spring-ai-azure-store and Spring AI core to matching versions so any new ExpressionType values are handled
  3. Catch RuntimeException around filter conversion and simplify the expression tree to only supported operators
  4. If you need an operator added, extend the switch in getOperationSymbol to map the missing type to its OData symbol

Example fix

// before
Expression e = new Expression(ExpressionType.GT, key, value);
String op = converter.getOperationSymbol(e); // ok only for comparisons
// after
Filter.ExpressionText text = new ExpressionText("year");
Filter.Expression e = GT(text, 2020); // build via Filter helper methods; convert whole tree with converter.convertExpression(expression)
Defensive patterns

Strategy: try-catch

Validate before calling

private static final Set<ExpressionType> SUPPORTED = Set.of(ExpressionType.LT, ExpressionType.LTE, ExpressionType.GT, ExpressionType.GTE, ExpressionType.IN, ExpressionType.NIN);
if (expr instanceof Expression e && !SUPPORTED.contains(e.type())) { throw new IllegalArgumentException("Azure converter only supports comparison types, got: " + e.type()); }

Type guard

boolean isAzureComparable(Filter.Operand o) { return o instanceof Expression e && Set.of(ExpressionType.LT, ExpressionType.LTE, ExpressionType.GT, ExpressionType.GTE, ExpressionType.IN, ExpressionType.NIN).contains(e.type()); }

Try / catch

try { String filter = azureConverter.convertExpression(expression); ... } catch (RuntimeException e) { log.warn("Unsupported Azure filter expression: {}", e.getMessage()); /* fallback to unfiltered or client-side filtering */ }

Prevention

When it happens

Trigger: Calling the converter (directly or via AzureAiSearchVectorStore with similaritySearch(SearchRequest.builder().filterExpression(...))) with a Filter.Expression whose type() is not IN, NIN, LT, LTE, GT, or GTE — e.g. a raw Expression of type AND/OR/NOT that bypassed doExpression's normal grouping, or a newly added Filter.ExpressionType enum value in a newer Spring AI version not yet handled by this converter.

Common situations: Using a new Spring AI release that introduces new Filter.ExpressionType constants while the azure-store version is older; programmatically building Filter expressions and handing a group expression straight to getOperationSymbol instead of going through convertExpression/doExpression; custom subclasses calling getOperationSymbol directly.

Related errors


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