{"record":{"id":"fa4c169b5df29b25","repo":"spring-projects/spring-ai","slug":"failed-to-add-document-to-index","errorCode":null,"errorMessage":"Failed to add document to index","messagePattern":"Failed to add document to index","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"spring-ai-tool-search-tool/src/main/java/org/springframework/ai/tool/toolsearch/index/lucene/LuceneToolIndex.java","lineNumber":193,"sourceCode":"\t * document is silently dropped (the session was cleared anyway).\n\t * @param sessionId the session ID associated with the tool\n\t * @param id unique identifier for the tool\n\t * @param toolName name of the tool\n\t * @param toolDescription description of the tool (searchable)\n\t */\n\tpublic void add(String sessionId, String id, String toolName, String toolDescription) {\n\t\ttry {\n\t\t\tSessionIndex sessionIndex = getOrCreateSessionIndex(sessionId);\n\t\t\tDocument doc = this.createDocument(sessionId, id, toolName, toolDescription);\n\t\t\tsessionIndex.writer.addDocument(doc);\n\t\t}\n\t\tcatch (AlreadyClosedException ex) {\n\t\t\tif (logger.isWarnEnabled()) {\n\t\t\t\tlogger.warn(\"Skipping add for session '\" + sessionId + \"': index was concurrently cleared\");\n\t\t\t}\n\t\t}\n\t\tcatch (IOException e) {\n\t\t\tthrow new RuntimeException(\"Failed to add document to index\", e);\n\t\t}\n\t}\n\n\t/**\n\t * Commits all pending changes to all session indexes. Call this after batch additions\n\t * for better performance.\n\t */\n\tpublic void commit() {\n\t\tfor (Map.Entry<String, SessionIndex> entry : this.sessionIndexes.entrySet()) {\n\t\t\ttry {\n\t\t\t\tSessionIndex sessionIndex = entry.getValue();\n\t\t\t\tsessionIndex.writer.commit();\n\t\t\t\tsessionIndex.refreshReader();\n\t\t\t}\n\t\t\tcatch (IOException e) {\n\t\t\t\tthrow new RuntimeException(\"Failed to commit changes to index for session: \" + entry.getKey(), e);\n\t\t\t}\n\t\t}","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/spring-projects/spring-ai/blob/98a7beda4f29d80a71c5837eb4053b03a93a46f7/spring-ai-tool-search-tool/src/main/java/org/springframework/ai/tool/toolsearch/index/lucene/LuceneToolIndex.java#L175-L211","documentation":"SessionIndex.add() adds a tool document to the session's Lucene index via indexTool/indexTools. If the write throws an IOException it is wrapped in this RuntimeException. AlreadyClosedException is intentionally swallowed with a warning (index concurrently cleared), so this error represents a genuine IO write failure, not concurrent clearing.","triggerScenarios":"Calling indexTool(sessionId, toolReference) or indexTools(...) when the Lucene writer hits an IOException: disk full, closed directory/channel, lock acquisition failure, or corrupted index state.","commonSituations":"Disk exhaustion on the index volume, writing after the backing directory was deleted externally, too many open files (ulimit) exhausting file descriptors, or index corruption after a crash.","solutions":["Check the wrapped IOException cause; fix the root IO condition (disk space, permissions, file descriptors).","Raise the open-file ulimit if 'Too many open files' appears; session indexes each hold Lucene resources.","Call commit() (or commitAll) after batch additions and ensure clearIndex/index operations are not racing.","If the index is corrupted, clear and rebuild it by re-indexing the session's tools."],"exampleFix":"// before\nfor (ToolReference t : tools) { index.indexTool(sessionId, t); } // many session indexes open, fd exhaustion\n// after\nindex.indexTools(sessionId, tools); // batch API\nindex.commitAll();","handlingStrategy":"try-catch","validationCode":"// Pre-check filesystem capacity before bulk indexing\nif (dir.getUsableSpace() < MIN_FREE_BYTES) {\n    throw new IllegalStateException(\"Insufficient disk space for tool index\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    toolIndex.indexTool(sessionId, toolReference);\n} catch (RuntimeException e) {\n    if (e.getMessage() != null && e.getMessage().equals(\"Failed to add document to index\")) {\n        logger.error(\"Lucene write failed: {}\", e.getCause(), e);\n        toolIndex.clearIndex(sessionId);\n        // re-index session tools after rebuild\n    } else { throw e; }\n}","preventionTips":["Raise ulimit -n for processes holding many session indexes.","Monitor free disk space and fd counts on the index volume.","Batch additions with indexTools + commitAll() instead of per-tool writes.","Rebuild the index if IOExceptions persist (possible corruption)."],"tags":["lucene","index","io","write-failed"],"backgroundTag":"file-write-failed","analyzedSha":"98a7beda4f29d80a71c5837eb4053b03a93a46f7","analyzedAt":"2026-09-11T14:15:49.441Z","contentChangedAt":"2026-09-11T14:15:49.441Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}