spring-projects/spring-ai · warning
Skipping add for session
Error message
Skipping add for session '${sessionId}': index was concurrently cleared What it means
During LuceneToolIndex.add, if the per-session index writer was closed concurrently (e.g. by a clear() call on another thread), Lucene throws AlreadyClosedException. The index logs this warning and skips the add instead of failing, because the session was intentionally discarded. It reflects a benign race between indexing and clearing.
Solutions
- Treat the warning as benign: the session was cleared, so the skipped document is intentionally discarded.
- Synchronize session lifecycle: clear() the session only after all pending indexTool calls complete for that sessionId.
- Check ordering in your code — don't index tools into a session you are simultaneously clearing.
- If documents are needed post-clear, re-add them after the clear completes; a new SessionIndex will be created lazily.
Example fix
// before: racing clear and add executor.submit(() -> index.indexTools(sessionId, tools)); index.clear(sessionId); // may close writer mid-add // after: clear after indexing completes Future<?> f = executor.submit(() -> index.indexTools(sessionId, tools)); f.get(); index.clear(sessionId);
Defensive patterns
Strategy: try-catch
Try / catch
// AlreadyClosedException inside add is swallowed by the library with a warning;
// coordinate lifecycle at call site:
synchronized (sessionLock) {
index.indexTools(sessionId, tools);
} Prevention
- Do not call clear(sessionId) concurrently with indexTool calls for the same session.
- Complete indexing before session teardown.
- Centralize session lifecycle management in one component.
- Treat this warning as expected noise when clearing sessions is routine.
When it happens
Trigger: Calling indexTool/indexTools (which call add) for a sessionId at nearly the same moment another thread calls clear() on that session, closing the writer; retry/replay of indexing after session cleanup.
Common situations: Concurrent tool registration while an HTTP session or agent session is torn down; scheduled indexing jobs racing with user-initiated session clears; multiplexed requests sharing a sessionId whose lifecycle is managed elsewhere.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- No sessionId provided in ToolSearchRequest, returning empty…
- Failed to add document to index
- Failed to clear the index for session:
- 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/3b3af61db26c5ce4.
Report an issue: GitHub.
Appendix: source
Thrown at spring-ai-tool-search-tool/src/main/java/org/springframework/ai/tool/toolsearch/index/lucene/LuceneToolIndex.java:189
* {@link #clearIndex(String)} is called concurrently for the same session from a
* different thread. The advisor's built-in flow prevents this via the atomic
* fingerprint-check in {@code initializeSession()}. Direct callers must ensure that
* no concurrent {@code clearIndex()} runs for the same session; if one does, the
* document is silently dropped (the session was cleared anyway).
* @param sessionId the session ID associated with the tool
* @param id unique identifier for the tool
* @param toolName name of the tool
* @param toolDescription description of the tool (searchable)
*/
public void add(String sessionId, String id, String toolName, String toolDescription) {
try {
SessionIndex sessionIndex = getOrCreateSessionIndex(sessionId);
Document doc = this.createDocument(sessionId, id, toolName, toolDescription);
sessionIndex.writer.addDocument(doc);
}
catch (AlreadyClosedException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Skipping add for session '" + sessionId + "': index was concurrently cleared");
}
}
catch (IOException e) {
throw new RuntimeException("Failed to add document to index", e);
}
}
/**
* Commits all pending changes to all session indexes. Call this after batch additions
* for better performance.
*/
public void commit() {
for (Map.Entry<String, SessionIndex> entry : this.sessionIndexes.entrySet()) {
try {
SessionIndex sessionIndex = entry.getValue();
sessionIndex.writer.commit();
sessionIndex.refreshReader();
}View on GitHub (pinned to 98a7beda4f)