{"record":{"id":"39c227e717011001","repo":"unslothai/unsloth","slug":"delete-failed-res-status","errorCode":null,"errorMessage":"Delete failed (${res.status})","messagePattern":"Delete failed \\((.+?)\\)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"studio/frontend/src/features/chat/api/prompts-api.ts","lineNumber":48,"sourceCode":"\nexport async function listPromptEntries(): Promise<PromptEntry[]> {\n  const res = await authFetch(\"/api/prompts/entries\");\n  const data = await parseJsonOrThrow<{ entries: PromptEntry[] }>(res);\n  return data.entries;\n}\n\nexport async function savePromptEntry(entry: PromptEntry): Promise<PromptEntry> {\n  const res = await authFetch(`/api/prompts/entries/${entry.id}`, {\n    method: \"PUT\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify(entry),\n  });\n  return parseJsonOrThrow<PromptEntry>(res);\n}\n\nexport async function deletePromptEntry(id: string): Promise<void> {\n  const res = await authFetch(`/api/prompts/entries/${id}`, { method: \"DELETE\" });\n  if (!res.ok) throw new Error(`Delete failed (${res.status})`);\n}\n\nexport async function bulkSavePromptEntries(entries: PromptEntry[]): Promise<number> {\n  if (!entries.length) return 0;\n  const res = await authFetch(\"/api/prompts/entries/bulk\", {\n    method: \"POST\",\n    headers: { \"Content-Type\": \"application/json\" },\n    body: JSON.stringify({ entries }),\n  });\n  const data = await parseJsonOrThrow<{ count: number }>(res);\n  return data.count;\n}\n\nexport async function listPromptLists(): Promise<PromptListEntry[]> {\n  const res = await authFetch(\"/api/prompts/lists\");\n  const data = await parseJsonOrThrow<{ lists: PromptListEntry[] }>(res);\n  return data.lists;\n}","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/frontend/src/features/chat/api/prompts-api.ts#L30-L66","documentation":"Thrown by deletePromptEntry when DELETE /api/prompts/entries/:id returns non-2xx. Unlike save/bulk (which route through parseJsonOrThrow), the delete path has no body parsing — only the numeric status is reported. The entry therefore remains in local state.","triggerScenarios":"Deleting a prompt entry that is concurrently deleted elsewhere (non-404 error), deleting with expired auth (401), or backend failure (5xx).","commonSituations":"Two tabs deleting the same entry where the server does not return 404-or-2xx for the loser; session expired before the delete click; backend restart mid-operation.","solutions":["Re-auth if 401, retry after backend recovery if 5xx.","On repeated failure, refresh the entries list and retry against fresh state.","Consider treating 404 as success if the UX allows (pattern already used in providers deleteProviderConfig)."],"exampleFix":"// before\nif (!res.ok) throw new Error(`Delete failed (${res.status})`);\n\n// after\nif (res.status === 404) return; // already deleted elsewhere\nif (!res.ok) throw new Error(`Delete failed (${res.status})`);","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await deletePromptEntry(id); }\ncatch (e) {\n  if (/\\(404\\)$/.test(e.message)) { removeEntryLocally(id); return; } // already gone\n  showError(e.message);\n}","preventionTips":["Handle 404 as success for delete-by-id (matches providers-api pattern).","Refresh entries before delete sweeps to avoid stale ids.","Disable the delete button while a delete is in flight to avoid double submits."],"tags":["prompts","delete","http","concurrency"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}