{"record":{"id":"8c0290a7e7e1ed52","repo":"Mintplex-Labs/anything-llm","slug":"thread-threadslug-not-found","errorCode":null,"errorMessage":"Thread ${threadSlug} not found.","messagePattern":"Thread (.+?) not found\\.","errorType":"http","errorClass":null,"httpStatus":404,"severity":"warning","filePath":"server/endpoints/api/workspaceThread/index.js","lineNumber":419,"sourceCode":"        const workspace = await Workspace.get({ slug: String(slug) });\n        if (!workspace) {\n          response.status(404).json({\n            id: uuidv4(),\n            type: \"abort\",\n            textResponse: null,\n            sources: [],\n            close: true,\n            error: `Workspace ${slug} not found.`,\n          });\n          return;\n        }\n\n        const thread = await WorkspaceThread.get({\n          slug: String(threadSlug),\n          workspace_id: workspace.id,\n        });\n        if (!thread) {\n          response.status(404).json({\n            id: uuidv4(),\n            type: \"abort\",\n            textResponse: null,\n            sources: [],\n            close: true,\n            error: `Thread ${threadSlug} not found.`,\n          });\n          return;\n        }\n\n        const resolvedMode = mode ?? workspace.chatMode;\n        if (\n          (!message?.length || !VALID_CHAT_MODE.includes(resolvedMode)) &&\n          !reset\n        ) {\n          response.status(400).json({\n            id: uuidv4(),\n            type: \"abort\",","sourceCodeStart":401,"sourceCodeEnd":437,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/api/workspaceThread/index.js#L401-L437","documentation":"HTTP 404 from POST /api/v1/workspace/:slug/thread/:threadSlug/chat when WorkspaceThread.get({slug:threadSlug, workspace_id}) finds no thread. The thread must belong to the resolved workspace; a thread that exists elsewhere still fails. The abort-shaped body names the missing threadSlug specifically, distinguishing it from the workspace-level 404.","triggerScenarios":"Correct workspace, wrong or deleted thread slug; thread name used instead of slug; thread removed by another user/session between listing and chatting.","commonSituations":"Long-lived clients caching a threadSlug past deletion; concurrent users pruning threads; UI deep-links to removed threads.","solutions":["List threads for the workspace and use a current slug","If missing, create the thread: POST /api/v1/workspace/:slug/thread/new, then chat using the returned slug","On 404, invalidate the cached thread and re-resolve once","Ensure the threadSlug comes from the API response field slug, not name"],"exampleFix":"// before\nconst res = await chat(slug, cachedThreadSlug, message);\n// after\nlet threadSlug = cachedThreadSlug;\nif (!(await threadExists(slug, threadSlug)))\n  threadSlug = (await createThread(slug, { name: 'recovered' })).slug;\nconst res = await chat(slug, threadSlug, message);","handlingStrategy":"fallback","validationCode":"if (!(await threadExists(slug, threadSlug)))\n  threadSlug = (await createThread(slug, { name: 'auto-recovered' })).slug;","typeGuard":"function isThreadNotFound(d) { return d?.type === 'abort' && /Thread .* not found/.test(d.error ?? ''); }","tryCatchPattern":"try { await threadChat(slug, threadSlug, msg); }\ncatch (e) { if (isThreadNotFound(e.payload)) { threadSlug = await createThread(slug); await threadChat(slug, threadSlug, msg); } else throw e; }","preventionTips":["Store the thread slug from the create response","Revalidate thread before long-running sessions","Auto-create the thread on 404 when idempotency is acceptable"],"tags":["anythingllm","developer-api","workspace-thread","chat","http-404","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}