spring-projects/spring-ai · error · RuntimeException
Failed to search index
Error message
Failed to search index
What it means
Thrown by LuceneToolIndex.doSearch() (called from search()) when the Lucene search pipeline fails with an IOException: opening/reusing the IndexReader (ensureAndGetReader), executing searcher.search(), or reading stored fields in extractToolReferences. The library wraps it as a RuntimeException("Failed to search index") because IOException is checked but the search API is not declared to throw.
Source
Thrown at spring-ai-tool-search-tool/src/main/java/org/springframework/ai/tool/toolsearch/index/lucene/LuceneToolIndex.java:253
* @param queryString the search query
* @param maxResults maximum number of results to return
* @param minScore minimum score threshold for results
* @return list of matching documents
*/
private ToolSearchResponse doSearch(SessionIndex sessionIndex, String queryString, int maxResults, float minScore) {
try {
IndexSearcher searcher = new IndexSearcher(sessionIndex.ensureAndGetReader());
Query query = buildQuery(queryString);
if (query == null) {
return ToolSearchResponse.builder().build();
}
TopDocs results = searcher.search(query, maxResults);
return this.extractToolReferences(queryString, searcher, results, minScore);
}
catch (IOException e) {
throw new RuntimeException("Failed to search index", e);
}
}
private ToolSearchResponse extractToolReferences(String query, IndexSearcher searcher, TopDocs results,
float minScore) throws IOException {
List<ToolReference> foundToolReferences = new ArrayList<>(results.scoreDocs.length);
StoredFields storedFields = searcher.storedFields();
for (ScoreDoc scoreDoc : results.scoreDocs) {
if (logger.isInfoEnabled()) {
logger.info("Score: " + scoreDoc.score + ", name: "
+ storedFields.document(scoreDoc.doc).get(FIELD_TOOL_NAME));
}
if (scoreDoc.score >= minScore) {
var doc = storedFields.document(scoreDoc.doc);
foundToolReferences.add(ToolReference.builder()
.relevanceScore(scoreDoc.score)
.toolName(doc.get(FIELD_TOOL_NAME))View on GitHub (pinned to 98a7beda4f)
Solutions
- Inspect the wrapped IOException cause to see which step failed (reader open, search, stored-fields fetch)
- Verify the index directory exists and is readable/writable by the process
- Ensure no clearIndex() or close() runs concurrently with search() for the same session
- If reader/index is stale or corrupt, re-initialize the session (re-add documents) and search again
- Catch the RuntimeException and return an empty ToolSearchResponse as a graceful fallback in the advisor flow
Example fix
// before
ToolSearchResponse resp = index.search(sessionId, "sql query", 5, 0.5f); // throws RuntimeException on IO failure
// after
ToolSearchResponse resp;
try {
resp = index.search(sessionId, "sql query", 5, 0.5f);
}
catch (RuntimeException e) {
logger.warn("tool search failed, returning empty result", e);
resp = ToolSearchResponse.builder().toolReferences(List.of()).totalMatches(0).build();
} Defensive patterns
Strategy: fallback
Validate before calling
File idxDir = new File(indexPath);
if (!idxDir.isDirectory() || !Files.isReadable(idxDir.toPath())) {
throw new IllegalStateException("Index directory missing or unreadable: " + indexPath);
} Try / catch
ToolSearchResponse resp;
try {
resp = index.search(sessionId, query, maxResults, minScore);
}
catch (RuntimeException e) {
if (e.getCause() instanceof java.io.IOException) {
logger.warn("Lucene search IO failure for session " + sessionId, e);
}
resp = ToolSearchResponse.builder().toolReferences(List.of()).totalMatches(0).build();
} Prevention
- Ensure no clearIndex()/close() runs concurrently with search() on the same session
- Keep the index directory on stable, readable local storage
- Rebuild the index on startup if segment files are detected as corrupt
- Return an empty ToolSearchResponse as graceful degradation so the advisor flow continues
When it happens
Trigger: Calling search() when the session's index directory is unreadable or deleted, the IndexReader was closed by a concurrent clearIndex(), the underlying index files are corrupt, or an I/O error occurs while fetching stored documents for the matched score docs.
Common situations: Index directory removed or remounted read-only between add and search; reader closed by concurrent clearIndex()/close(); corrupted segment files after a crash mid-commit; NFS/network storage dropping the index directory; searching after the index was rebuilt with an incompatible Lucene version.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to initialize Lucene index for session:
- Failed to clear the index for session:
- Failed to add document to index
- Failed to commit changes to index for session:
- Failed to delete document from index
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/9be7fdfdce802124.
Report an issue: GitHub.