spring-projects/spring-ai · warning
VectorToolIndex does not support categoryFilter
Error message
VectorToolIndex does not support categoryFilter — '${categoryFilter}' will be ignored and results will not be narrowed by category. What it means
VectorToolIndex performs semantic similarity search over a vector store and does not implement category-based filtering. If a ToolSearchRequest carries a categoryFilter, it logs this warning and ignores the filter, returning results narrowed only by similarity — never by category.
Solutions
- Remove categoryFilter from requests sent to VectorToolIndex or accept unfiltered semantic results.
- Switch to LuceneToolIndex or RegexToolIndex if category filtering is required.
- Embed category information into tool descriptions and/or include category terms in the query so semantic search effectively narrows results.
- Post-filter the returned ToolSearchResponse results by category in application code.
Example fix
// before: filter silently ignored
vectorToolIndex.search(ToolSearchRequest.builder().query("weather").categoryFilter("travel").build());
// after: include category signal in query or post-filter
var resp = vectorToolIndex.search(ToolSearchRequest.builder().query("weather").build());
var filtered = resp.tools().stream().filter(t -> "travel".equals(t.category())).toList(); Defensive patterns
Strategy: fallback
Prevention
- Don't set categoryFilter when using VectorToolIndex.
- Choose LuceneToolIndex/RegexToolIndex when category filtering matters.
- Bake category keywords into tool descriptions for semantic narrowing.
- Post-filter results in application code as a fallback.
When it happens
Trigger: Calling search on a VectorToolIndex with ToolSearchRequest.builder().categoryFilter("...").build(); the filter value is logged and discarded.
Common situations: Reusing request-building code shared with Lucene/Regex indexes that support categoryFilter; switching the index backend from LuceneToolIndex to VectorToolIndex assuming feature parity; users adding categories to metadata expecting filtering.
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
- Bad Request
- Cannot compare values of incompatible types
- Cannot compare values of incompatible types
- Cannot compare values of types
- Cannot compare values of types
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/c447be93490422c2.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-tool-search-tool/src/main/java/org/springframework/ai/tool/toolsearch/index/vectorstore/VectorToolIndex.java:135
documents.add(new Document(id, ref.summary(), Map.of(METADATA_SESSION_ID, sessionId, METADATA_ID, id,
METADATA_TOOL_NAME, ref.toolName(), METADATA_TOOL_DESCRIPTION, ref.summary())));
}
this.vectorStore.add(documents);
this.sessionToolIds.compute(sessionId, (k, existing) -> {
List<String> list = existing != null ? new ArrayList<>(existing) : new ArrayList<>(ids.size());
list.addAll(ids);
return list;
});
if (logger.isInfoEnabled()) {
logger.info("Indexed " + documents.size() + " tools for sessionId=" + sessionId);
}
}
@Override
public ToolSearchResponse search(ToolSearchRequest toolSearchRequest) {
if (toolSearchRequest.categoryFilter() != null && logger.isWarnEnabled()) {
logger.warn("VectorToolIndex does not support categoryFilter — '" + toolSearchRequest.categoryFilter()
+ "' will be ignored and results will not be narrowed by category.");
}
int maxResults = toolSearchRequest.maxResults() != null ? toolSearchRequest.maxResults() : DEFAULT_MAX_RESULTS;
List<Document> docs = this.doSearch(toolSearchRequest.query(), toolSearchRequest.sessionId(), maxResults,
DEFAULT_SIMILARITY_THRESHOLD);
List<ToolReference> toolReferences = docs.stream()
.map(doc -> ToolReference.builder()
.toolName((String) Objects.requireNonNull(doc.getMetadata().get(METADATA_TOOL_NAME)))
.relevanceScore(Objects.requireNonNullElse(doc.getScore(), 0.0))
.summary((String) Objects.requireNonNull(doc.getMetadata().get(METADATA_TOOL_DESCRIPTION)))
.build())
.toList();
return ToolSearchResponse.builder()
.toolReferences(toolReferences)
.totalMatches(toolReferences.size())View on GitHub (pinned to 98a7beda4f)