{"record":{"id":"e5315007a69efec8","repo":"alibaba/spring-ai-alibaba","slug":"thread-already-exists-e53150","errorCode":null,"errorMessage":"Thread already exists: ","messagePattern":"Thread already exists: ","errorType":"http","errorClass":"ResponseStatusException","httpStatus":400,"severity":"warning","filePath":"spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/controller/ThreadController.java","lineNumber":181,"sourceCode":"\t */\n\t@PostMapping(\"/apps/{appName}/users/{userId}/threads/{threadId}\")\n\tpublic Thread createThreadWithId(\n\t\t\t@PathVariable String appName,\n\t\t\t@PathVariable String userId,\n\t\t\t@PathVariable String threadId,\n\t\t\t@RequestBody(required = false) Map<String, Object> state) {\n\t\tlog.info(\n\t\t\t\t\"Request received for POST /apps/{}/users/{}/threads/{} with state: {}\",\n\t\t\t\tappName,\n\t\t\t\tuserId,\n\t\t\t\tthreadId,\n\t\t\t\tstate);\n\n\t\ttry {\n\t\t\tfindThreadOrThrow(appName, userId, threadId);\n\n\t\t\tlog.warn(\"Attempted to create thread with existing ID: {}\", threadId);\n\t\t\tthrow new ResponseStatusException(\n\t\t\t\t\tHttpStatus.BAD_REQUEST, \"Thread already exists: \" + threadId);\n\t\t}\n\t\tcatch (ResponseStatusException e) {\n\n\t\t\tif (e.getStatusCode() != HttpStatus.NOT_FOUND) {\n\t\t\t\tthrow e;\n\t\t\t}\n\n\t\t\tlog.info(\"Thread {} not found, proceeding with creation.\", threadId);\n\t\t}\n\n\t\tMap<String, Object> initialState = (state != null) ? state : Collections.emptyMap();\n\t\ttry {\n\t\t\tThread createdThread =\n\t\t\t\t\tthreadService\n\t\t\t\t\t\t\t.createThread(appName, userId, new ConcurrentHashMap<>(initialState), threadId)\n\t\t\t\t\t\t\t.block();\n","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-studio/src/main/java/com/alibaba/cloud/ai/agent/studio/controller/ThreadController.java#L163-L199","documentation":"ThreadController.createThreadWithId throws 400 BAD_REQUEST 'Thread already exists: <threadId>' when the pre-check findThreadOrThrow succeeds, meaning a thread with that ID already exists for the app/user. Client-supplied thread IDs are treated as create-only: use PUT semantics elsewhere or delete first.","triggerScenarios":"POST to /apps/{appName}/users/{userId}/threads/{threadId} where the (appName, userId, threadId) triple already exists; duplicate form submissions; retry of an already-successful creation; two clients racing to create the same ID.","commonSituations":"Browser refresh resubmitting a POST; cron/setup scripts that run idempotently but POST with fixed IDs; test fixtures creating the same threadId across runs without cleanup.","solutions":["GET the thread first and skip creation if it already exists (idempotent client logic)","DELETE the existing thread then POST again if a fresh thread is intended","Use POST /apps/{appName}/users/{userId}/threads (no ID) to get a generated unique ID","Generate thread IDs with UUID.randomUUID() so collisions cannot occur","Handle the 400 status in your HTTP client and treat it as 'already created'"],"exampleFix":"// before\ngiven threadId=\"abc\": POST /apps/app/users/u/threads/abc  // 400 if exists\n// after\ntry { POST .../threads/abc } catch (HttpClientErrorException.BadRequest e) {\n    return GET .../threads/abc; // reuse existing\n}","handlingStrategy":"try-catch","validationCode":"boolean exists;\ntry { GET \"/apps/{a}/users/{u}/threads/{t}\"; exists = true; } catch (HttpClientErrorException.NotFound e) { exists = false; }\n// only POST when !exists","typeGuard":null,"tryCatchPattern":"try { return create(id); } catch (HttpClientErrorException.BadRequest e) { return get(id); } // idempotent create-or-get","preventionTips":["Implement create-or-get (upsert-style) client logic","Use the generated-ID endpoint when IDs are not semantically meaningful","Generate IDs with UUID.randomUUID()","Guard scheduled scripts with an existence check before POST"],"tags":["http","duplicate-resource","thread-management"],"backgroundTag":"file-already-exists","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"}