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

  1. Rename the metadata key in your documents to use only letters, digits, '_', '.', '-' (e.g. 'user_name').
  2. Sanitize/validate identifier strings before embedding them into Filter expressions (e.g. replace invalid characters).
  3. 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

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


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)