{"record":{"id":"a4db152cf7636319","repo":"alibaba/spring-ai-alibaba","slug":"threadid-is-not-allowed-to-be-null","errorCode":null,"errorMessage":"threadId is not allowed to be null","messagePattern":"threadId is not allowed to be null","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/checkpoint/savers/mongo/MongoSaver.java","lineNumber":292,"sourceCode":"\t\tDocument metaDoc = threadMetaCollection.find(clientSession, new BasicDBObject(\"_id\", metaId)).first();\n\n\t\tif (metaDoc != null) {\n\t\t\tString threadId = metaDoc.getString(FIELD_THREAD_ID);\n\t\t\tBoolean isReleased = metaDoc.getBoolean(FIELD_IS_RELEASED, false);\n\n\t\t\tif (threadId != null && !Boolean.TRUE.equals(isReleased)) {\n\t\t\t\treturn threadId;\n\t\t\t}\n\t\t}\n\n\t\treturn null; // No active thread exists\n\t}\n\n\t@Override\n\tpublic Collection<Checkpoint> list(RunnableConfig config) {\n\t\tOptional<String> threadNameOpt = config.threadId();\n\t\tif (!threadNameOpt.isPresent()) {\n\t\t\tthrow new IllegalArgumentException(\"threadId is not allowed to be null\");\n\t\t}\n\n\t\tString threadName = threadNameOpt.get();\n\t\tClientSession clientSession = this.client\n\t\t\t\t.startSession(ClientSessionOptions.builder().defaultTransactionOptions(txnOptions).build());\n\t\tclientSession.startTransaction();\n\t\tList<Checkpoint> checkpoints = null;\n\t\ttry {\n\t\t\t// Get active thread_id for the thread_name\n\t\t\tString threadId = getActiveThreadId(threadName, clientSession);\n\t\t\tif (threadId == null) {\n\t\t\t\tclientSession.commitTransaction();\n\t\t\t\treturn Collections.emptyList();\n\t\t\t}\n\n\t\t\t// Use thread_id to query checkpoints\n\t\t\tMongoCollection<Document> collection = database.getCollection(CHECKPOINT_COLLECTION);\n\t\t\tString checkpointId = CHECKPOINT_PREFIX + threadId;","sourceCodeStart":274,"sourceCodeEnd":310,"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/mongo/MongoSaver.java#L274-L310","documentation":"MongoSaver.list() requires a checkpoint thread to operate on; the threadId inside the supplied RunnableConfig must be present. If config.threadId() returns an empty Optional, the saver cannot scope the Mongo query to a thread and throws this IllegalArgumentException immediately, before any database session is opened.","triggerScenarios":"Calling MongoSaver.list(config) with a RunnableConfig that was built without a threadId, or one whose threadId was explicitly set to null.","commonSituations":"Building a RunnableConfig programmatically and forgetting threadId; reusing a default/empty config object; a null threadId propagating from an upstream API that treated 'no thread' as a valid state.","solutions":["Build the RunnableConfig with a non-null threadId before calling list(), e.g. RunnableConfig.builder().threadId(\"my-thread\").build()","Call config.threadId() (or Optional.isPresent) yourself before invoking list() and fail fast with a clear application-level message","If the thread is genuinely unknown, do not call list(); list all threads via the release/tag APIs or initialize a new thread by putting a checkpoint first"],"exampleFix":"// before\nsaver.list(RunnableConfig.builder().build());\n// after\nsaver.list(RunnableConfig.builder().threadId(\"session-123\").build());","handlingStrategy":"validation","validationCode":"RunnableConfig cfg = /* ... */;\nif (cfg == null || cfg.threadId() == null || !cfg.threadId().isPresent()) {\n    throw new IllegalArgumentException(\"list() requires a non-null threadId\");\n}\nsaver.list(cfg);","typeGuard":"boolean hasThreadId(RunnableConfig cfg) {\n    return cfg != null && cfg.threadId() != null && cfg.threadId().isPresent();\n}","tryCatchPattern":"try {\n    saver.list(cfg);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"threadId\")) {\n        throw new IllegalStateException(\"RunnableConfig must include threadId\", e);\n    }\n    throw e;\n}","preventionTips":["Always build RunnableConfig via builder with an explicit threadId","Add a shared helper that validates threadId before any saver call","Centralize config creation so threadId cannot be omitted"],"tags":["java","mongo","checkpoint","null-thread-id"],"backgroundTag":"missing-required-argument","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}