{"record":{"id":"c4d5eee99291f206","repo":"different-ai/openwork","slug":"failed-to-save-provider-response-status","errorCode":null,"errorMessage":"Failed to save provider (${response.status}).","messagePattern":"Failed to save provider \\((.+?)\\)\\.","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"ee/apps/den-web/app/(den)/dashboard/_components/llm-provider-editor-screen.tsx","lineNumber":765,"sourceCode":"                body.apiKey = apiKey.trim();\n            }\n\n            const path = provider\n                ? `/v1/llm-providers/${encodeURIComponent(provider.id)}`\n                : `/v1/llm-providers`;\n            const method = provider ? \"PATCH\" : \"POST\";\n\n            const { response, payload } = await requestJson(\n                path,\n                {\n                    method,\n                    body: JSON.stringify(body),\n                },\n                20000,\n            );\n\n            if (!response.ok) {\n                throw getRequestError(payload, response, `Failed to save provider (${response.status}).`);\n            }\n\n            const nextProvider =\n                payload &&\n                typeof payload === \"object\" &&\n                payload &&\n                \"llmProvider\" in payload &&\n                payload.llmProvider &&\n                typeof payload.llmProvider === \"object\"\n                    ? (payload.llmProvider as { id?: unknown })\n                    : null;\n            const nextProviderId =\n                typeof nextProvider?.id === \"string\"\n                    ? nextProvider.id\n                    : (provider?.id ?? null);\n            if (!nextProviderId) {\n                throw new Error(\n                    \"The provider was saved, but no provider id was returned.\",","sourceCodeStart":747,"sourceCodeEnd":783,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-web/app/(den)/dashboard/_components/llm-provider-editor-screen.tsx#L747-L783","documentation":"Thrown by saveProvider in llm-provider-editor-screen.tsx when the POST/PUT that creates or updates an LLM provider (20s timeout) returns non-ok. The thrown error comes from getRequestError (den-flow.ts:527): a ReauthRequiredError for 403 {error:'reauth'}, otherwise the server's `error` message or the fallback \"Failed to save provider (<status>).\".","triggerScenarios":"Saving provider settings (endpoint, API key, model list) returns non-ok: 400/422 (invalid base URL, malformed key, unsupported model id, bad JSON body), 401/403 (insufficient org role, expired session), 404 (provider was deleted while editing), 409 (duplicate provider name), 5xx, or exceeds the 20000ms timeout.","commonSituations":"Pasting an API key with whitespace/newlines or wrong provider prefix; using an internal base URL the Den server cannot reach; renaming to a name that already exists; the provider being removed by another admin mid-edit; server-side validation of model ids failing after a models list update.","solutions":["Validate inputs client-side before submit: trim the API key, check base URL format, and ensure the model ids exist (the editor already builds `body` — sanitize before JSON.stringify).","On 409, pick a unique provider name.","On 401/403, run reauth (isReauthRequiredError) or confirm the user has admin rights.","On 404, reload the provider list — the record was deleted by someone else."],"exampleFix":"// before\nif (!response.ok) {\n  throw getRequestError(payload, response, `Failed to save provider (${response.status}).`);\n}\n// after\nconst apiKey = input.apiKey.trim();\nif (apiKey.length === 0) throw new Error(\"API key is required.\");\nif (!response.ok) {\n  throw getRequestError(payload, response, `Failed to save provider (${response.status}).`);\n}","handlingStrategy":"validation","validationCode":"// before saveProvider\nconst apiKey = form.apiKey.trim();\nif (apiKey.length === 0) throw new Error(\"API key is required.\");\ntry { new URL(form.baseUrl); } catch { throw new Error(\"Base URL must be a valid URL.\"); }\nif (form.name.trim().length === 0) throw new Error(\"Name is required.\");\nconst duplicate = providers.some((p) => p.name === form.name.trim() && p.id !== form.id);\nif (duplicate) throw new Error(\"A provider with this name already exists.\");","typeGuard":"function isReauthError(e: unknown): e is ReauthRequiredError {\n  return e instanceof ReauthRequiredError;\n}","tryCatchPattern":"try {\n  await saveProvider(orgSlug, payload);\n} catch (error) {\n  if (isReauthError(error)) { startReauth(); return; }\n  if (/\\(409\\)/.test(error.message)) { setFieldError(\"name\", \"Name already in use.\"); return; }\n  setFormError(error.message);\n}","preventionTips":["Validate name uniqueness, URL format, and key format client-side with Zod before submit.","Trim and sanitize the API key before JSON.stringify of the body.","Re-fetch the provider when the editor has been open a long time to catch concurrent deletes.","Show per-field server errors from the response payload instead of a generic toast."],"tags":["http","llm-providers","den-api","form-validation"],"backgroundTag":"http-non-ok-response","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}