{"record":{"id":"01e22d64672b8166","repo":"Mintplex-Labs/anything-llm","slug":"bad-request-01e22d","errorCode":null,"errorMessage":"Bad Request","messagePattern":"Bad Request","errorType":"http","errorClass":null,"httpStatus":400,"severity":"warning","filePath":"server/endpoints/api/workspace/index.js","lineNumber":253,"sourceCode":"    #swagger.parameters['slug'] = {\n        in: 'path',\n        description: 'Unique slug of workspace to delete',\n        required: true,\n        type: 'string'\n    }\n    #swagger.responses[403] = {\n      schema: {\n        \"$ref\": \"#/definitions/InvalidAPIKey\"\n      }\n    }\n    */\n      try {\n        const { slug = \"\" } = request.params;\n        const VectorDb = getVectorDbClass();\n        const workspace = await Workspace.get({ slug: String(slug) });\n\n        if (!workspace) {\n          response.sendStatus(400).end();\n          return;\n        }\n\n        const workspaceId = Number(workspace.id);\n        await WorkspaceChats.delete({ workspaceId: workspaceId });\n        await DocumentVectors.deleteForWorkspace(workspaceId);\n        await Document.delete({ workspaceId: workspaceId });\n        await Workspace.delete({ id: workspaceId });\n\n        await EventLogs.logEvent(\"api_workspace_deleted\", {\n          workspaceName: workspace?.name || \"Unknown Workspace\",\n        });\n        try {\n          await VectorDb[\"delete-namespace\"]({ namespace: slug });\n        } catch (e) {\n          console.error(e.message);\n        }\n        response.sendStatus(200).end();","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/Mintplex-Labs/anything-llm/blob/3aec848f2885144aa8f1e53b9731a04310d5d558/server/endpoints/api/workspace/index.js#L235-L271","documentation":"DELETE /v1/workspace/:slug resolves the slug via `Workspace.get({slug})`; when no workspace matches, the handler intentionally returns `response.sendStatus(400)` — AnythingLLM uses 400 Bad Request (not 404) for 'workspace slug not found' on this route. This is a client-side addressing error: the slug in the URL does not exist (never existed, was already deleted, or arrived URL-mangled). Deletion protection (WORKSPACE_DELETION_PROTECTION) is a different failure (403) and never produces this 400.","triggerScenarios":"Deleting with a typo'd or stale slug; double-deleting (second call finds nothing); a slug with special characters sent unencoded so Prisma matches a literal '%20'-style string; slug case mismatch since lookup is exact.","commonSituations":"Scripts that cache slugs across workspace recreations; UI/automation race where the workspace was renamed (new slug) between listing and deleting; trailing whitespace or slashes in the URL path.","solutions":["List live slugs with GET /v1/workspaces and copy the exact slug from the response","encodeURIComponent the slug when building the URL","Treat 400 on this route as 'not found': make delete flows idempotent by accepting 400 as already-deleted","If deletion must be impossible-by-policy, expect 403 from WORKSPACE_DELETION_PROTECTION instead and remove that env to allow deletes"],"exampleFix":"// before\nawait fetch(`${base}/api/v1/workspace/my workspace`, {method:'DELETE', headers});\n\n// after\nconst slugs = (await fetch(`${base}/api/v1/workspaces`, opts).then(r=>r.json())).workspaces.map(w=>w.slug);\nif (!slugs.includes('my workspace')) throw new Error('slug not found - nothing to delete');\nawait fetch(`${base}/api/v1/workspace/${encodeURIComponent('my workspace')}`, {method:'DELETE', headers});","handlingStrategy":"validation","validationCode":"const live = new Set((await fetch(`${base}/api/v1/workspaces`, opts).then(r=>r.json())).workspaces.map(w=>w.slug));\nif (!live.has(slug)) return 'already-deleted'; // 400 is this API's not-found","typeGuard":"const isDeletableSlug = (s) => typeof s === 'string' && s.trim().length > 0 && s === s.trim();","tryCatchPattern":"try { const r = await del(workspaceUrl(slug)); if (r.status===400) return {ok:true, note:'not found = nothing to delete'}; if (r.status===403) throw new Error('deletion protection enabled'); } catch (e) { throw e; }","preventionTips":["Fetch the slug fresh before every delete - renames change slugs","Treat 400 as not-found and make deletes idempotent","Expect 403 when WORKSPACE_DELETION_PROTECTION is set"],"tags":["anythingllm","workspace","slug","http-400","not-found"],"backgroundTag":"resource-not-found","analyzedSha":"3aec848f2885144aa8f1e53b9731a04310d5d558","analyzedAt":"2026-08-18T10:02:21.017Z","contentChangedAt":"2026-08-18T10:02:21.017Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}