{"record":{"id":"895b2dc995e930a4","repo":"spring-projects/spring-ai","slug":"not-allowed-filter-identifier-name","errorCode":null,"errorMessage":"Not allowed filter identifier name: ","messagePattern":"Not allowed filter identifier name: ","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverter.java","lineNumber":119,"sourceCode":"\t\t}\n\t\tcontext.append(prefixedIdentifier);\n\t}\n\n\t/**\n\t * Adds the metadata field prefix to the given identifier name. Azure AI Search\n\t * requires metadata fields to be prefixed with \"meta_\" to distinguish them from\n\t * system fields.\n\t * @param identifier the field identifier without prefix\n\t * @return the prefixed field identifier (e.g., \"meta_fieldName\")\n\t * @throws IllegalArgumentException if the identifier is not in the allowed list\n\t */\n\tpublic String withMetaPrefix(String identifier) {\n\n\t\tif (this.allowedIdentifierNames.contains(identifier)) {\n\t\t\treturn \"meta_\" + identifier;\n\t\t}\n\n\t\tthrow new IllegalArgumentException(\"Not allowed filter identifier name: \" + identifier);\n\t}\n\n\t@Override\n\tprotected void doValue(Filter.Value filterValue, StringBuilder context) {\n\t\tif (filterValue.value() instanceof List list) {\n\t\t\t// search.in(field, 'val1,val2,val3', ',') requires one string literal\n\t\t\tdoStartValueRange(filterValue, context);\n\t\t\tint c = 0;\n\t\t\tfor (Object v : list) {\n\t\t\t\tappendListElementContent(normalizeDateString(v), context);\n\t\t\t\tif (c++ < list.size() - 1) {\n\t\t\t\t\tthis.doAddValueRangeSpitter(filterValue, context);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.doEndValueRange(filterValue, context);\n\t\t}\n\t\telse {\n\t\t\tthis.doSingleValue(normalizeDateString(filterValue.value()), context);","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/vector-stores/spring-ai-azure-store/src/main/java/org/springframework/ai/vectorstore/azure/AzureAiSearchFilterExpressionConverter.java#L101-L137","documentation":"withMetaPrefix prefixes a filter identifier with 'meta_' so it maps to a metadata field in the Azure AI Search index, but only if the identifier appears in this converter's allowlist of permitted field names (allowedIdentifierNames). Any other identifier — typically a reserved Azure field like 'id' or a non-whitelisted metadata key — is rejected with an IllegalArgumentException.","triggerScenarios":"Building a filter expression that references an identifier not in the converter's allowedIdentifierNames, e.g. new ExpressionText(\"content\") or (\"id\") inside a filter passed to AzureAiSearchVectorStore.similaritySearch, or calling converter.withMetaPrefix(\"myCustomField\") directly when allowlist was configured without that name.","commonSituations":"Constructing a vector store with a Builder.metadataFields(...) allowlist but then filtering on a metadata key that was not registered; filtering on built-in Azure index fields (id, content, embedding) that must not be meta-prefixed; renaming a metadata key in documents without updating the allowlist.","solutions":["Register the identifier in the converter/Builder allowlist (e.g. via metadataFields when building AzureAiSearchVectorStore) so it is in allowedIdentifierNames","Filter only on fields declared in the index's metadataFields configuration","If the field is a native Azure index column, avoid the metadata path — reference it without the meta_ prefix rather than via withMetaPrefix","Catch IllegalArgumentException around filter construction/conversion and log which identifier was rejected"],"exampleFix":"// before\nAzureAiSearchVectorStore store = AzureAiSearchVectorStore.builder(client)\n    .metadataFields(MetadataField.tag(\"category\"))\n    .build();\n// filter on 'author' -> throws\n// after\nAzureAiSearchVectorStore store = AzureAiSearchVectorStore.builder(client)\n    .metadataFields(MetadataField.tag(\"category\"), MetadataField.tag(\"author\"))\n    .build(); // 'author' now passes withMetaPrefix -> meta_author","handlingStrategy":"validation","validationCode":"Set<String> allowed = /* metadata fields configured on the store */;\nif (!allowed.contains(identifier)) { throw new IllegalArgumentException(\"Identifier not registered for Azure filtering: \" + identifier); }","typeGuard":null,"tryCatchPattern":"try { String filter = azureConverter.convertExpression(expression); ... } catch (IllegalArgumentException e) { log.error(\"Filter identifier rejected: {}\", e.getMessage()); throw new InvalidRequestException(e); }","preventionTips":["Declare every filterable metadata field via MetadataField when building AzureAiSearchVectorStore","Keep the allowlist in sync with document metadata keys","Never filter on native Azure index columns through the metadata prefix path","Log rejected identifiers to catch config drift early"],"tags":["azure","filter-expression","identifier","allowlist"],"backgroundTag":"invalid-identifier","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}