{"record":{"id":"03135079146ef0e0","repo":"alibaba/spring-ai-alibaba","slug":"thread-s-not-found-or-already-released","errorCode":null,"errorMessage":"Thread '%s' not found or already released","messagePattern":"Thread '(.+?)' not found or already released","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"warning","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java","lineNumber":477,"sourceCode":"\t\t\tps.setString(index, threadId);\n\t\t\tps.executeUpdate();\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\tthrow new Exception(\"Unable to delete retained checkpoints\", ex);\n\t\t}\n\t}\n\n\t@Override\n\tprotected void releaseThread(String threadId) throws Exception {\n\t\tConnection conn = null;\n\t\ttry (Connection ignored = conn = getConnection()) {\n\t\t\tconn.setAutoCommit(false);\n\t\t\ttry (PreparedStatement ps = conn.prepareStatement(RELEASE_THREAD)) {\n\t\t\t\tps.setString(1, threadId);\n\t\t\t\tint rowsAffected = ps.executeUpdate();\n\t\t\t\tif (rowsAffected == 0) {\n\t\t\t\t\tconn.rollback();\n\t\t\t\t\tthrow new IllegalStateException(format(\"Thread '%s' not found or already released\", threadId));\n\t\t\t\t}\n\t\t\t}\n\t\t\tconn.commit();\n\t\t}\n\t\tcatch (SQLException ex) {\n\t\t\trollback(conn, threadId);\n\t\t\tthrow new Exception(\"Unable to release checkpoint\", ex);\n\t\t}\n\t}\n\n\tprotected Connection getConnection() throws SQLException {\n\t\treturn dataSource.getConnection();\n\t}\n\n\tprivate void rollback(Connection conn, String threadId) {\n\t\tif (conn == null) {\n\t\t\treturn;\n\t\t}","sourceCodeStart":459,"sourceCodeEnd":495,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/h2/H2Saver.java#L459-L495","documentation":"releaseThread throws IllegalStateException(\"Thread '%s' not found or already released\") when the RELEASE_THREAD UPDATE affects 0 rows, i.e. the threadId has no active row to release. The connection is rolled back before throwing; this is a logical not-found/already-done condition, not an SQL failure.","triggerScenarios":"Calling the thread-release API with a threadId that was never created, was already released (previous call succeeded), or whose rows were deleted from the checkpoints table.","commonSituations":"Double-invocation of cleanup/shutdown logic that releases the same thread twice; releasing a thread id obtained from a different database; cleanup running after retention already deleted the thread's checkpoints.","solutions":["Make release idempotent: treat this IllegalStateException as 'already released' and continue.","Verify the threadId is the active id for that thread in this database (check the threads table).","Guard the release call so it runs at most once per thread lifecycle.","If the id comes from another environment/database, re-fetch it from the correct source."],"exampleFix":"// before: shutdown hook releases twice\nreleaseThread(threadId); // IllegalStateException on 2nd call\n// after: idempotent release\ntry { releaseThread(threadId); }\ncatch (IllegalStateException e) { log.debug(\"thread {} already released\", threadId); }","handlingStrategy":"try-catch","validationCode":"Optional<String> active = saver.getActiveThreadId(threadName); if (active.isEmpty()) return; // nothing to release","typeGuard":null,"tryCatchPattern":"try { releaseThread(threadId); }\ncatch (IllegalStateException e) { log.debug(\"thread {} already released\", threadId); } // idempotent release","preventionTips":["Make thread release idempotent — catch and ignore this state","Release each thread exactly once (guard with a flag or lock)","Fetch threadIds from the same database instance used by the saver"],"tags":["database","not-found","thread","state"],"backgroundTag":"record-not-found","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}