spring-projects/spring-ai · error · RuntimeException

Failed to clear the index for session:

Error message

Failed to clear the index for session: 

What it means

clearIndex(sessionId) removes and closes the SessionIndex for the given session. If closing the Lucene index writer/reader throws an IOException, it is wrapped in a RuntimeException naming the session. This indicates the index resources for that session could not be cleanly released.

Source

Thrown at spring-ai-tool-search-tool/src/main/java/org/springframework/ai/tool/toolsearch/index/lucene/LuceneToolIndex.java:130

		return this.sessionIndexes.computeIfAbsent(sessionId, key -> {
			try {
				return new SessionIndex(this.analyzer);
			}
			catch (IOException e) {
				throw new RuntimeException("Failed to initialize Lucene index for session: " + sessionId, e);
			}
		});
	}

	@Override
	public void clearIndex(String sessionId) {
		SessionIndex sessionIndex = this.sessionIndexes.remove(sessionId);
		if (sessionIndex != null) {
			try {
				sessionIndex.close();
			}
			catch (IOException e) {
				throw new RuntimeException("Failed to clear the index for session: " + sessionId, e);
			}
		}
	}

	@Override
	public void indexTool(String sessionId, ToolReference toolReference) {
		this.add(sessionId, String.valueOf(this.counter.getAndIncrement()), toolReference.toolName(),
				toolReference.summary());
	}

	@Override
	public void indexTools(String sessionId, List<ToolReference> toolReferences) {
		for (ToolReference ref : toolReferences) {
			this.add(sessionId, String.valueOf(this.counter.getAndIncrement()), ref.toolName(), ref.summary());
		}
	}

	@Override

View on GitHub (pinned to 98a7beda4f)

Solutions

  1. Inspect the wrapped IOException cause to see whether it is an AlreadyClosedException, LockObtainFailedException, or generic IO error.
  2. Avoid calling clearIndex concurrently with indexTool/indexTools; synchronize or serialize clear and write operations per session.
  3. If the session index is unrecoverable, drop the directory contents (or recreate the index instance) for that session.
  4. Ensure the index directory still exists before clearing if an external process may have deleted it.

Example fix

// before
toolIndex.indexTool(sessionId, ref);
toolIndex.clearIndex(sessionId); // concurrent clear race
// after
synchronized (lock) {
    toolIndex.indexTool(sessionId, ref);
    toolIndex.clearIndex(sessionId);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Only clear when the session index exists and no writes are in flight
if (indexHasSession(sessionId) && !isIndexing.get()) {
    toolIndex.clearIndex(sessionId);
}

Try / catch

try {
    toolIndex.clearIndex(sessionId);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().startsWith("Failed to clear the index for session")) {
        logger.warn("Could not cleanly close index for {}: {}", sessionId, e.getCause());
        // treat session as cleared; rebuild index on next use
    } else { throw e; }
}

Prevention

When it happens

Trigger: Calling clearIndex (or a delete/clear API that routes to it) while the underlying Lucene index is in a bad state — e.g. an already-closed writer, a pending merge failure, or an IO error flushing uncommitted changes during close.

Common situations: Concurrent clear while another thread is indexing, closing indexes after the backing directory was removed, or a crashed process left the index needing recovery on close.

Related errors


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