different-ai/openwork · error · Error
Failed to save provider (${response.status}).
Error message
Failed to save provider (${response.status}). What it means
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>).".
Source
Thrown at ee/apps/den-web/app/(den)/dashboard/_components/llm-provider-editor-screen.tsx:765
body.apiKey = apiKey.trim();
}
const path = provider
? `/v1/llm-providers/${encodeURIComponent(provider.id)}`
: `/v1/llm-providers`;
const method = provider ? "PATCH" : "POST";
const { response, payload } = await requestJson(
path,
{
method,
body: JSON.stringify(body),
},
20000,
);
if (!response.ok) {
throw getRequestError(payload, response, `Failed to save provider (${response.status}).`);
}
const nextProvider =
payload &&
typeof payload === "object" &&
payload &&
"llmProvider" in payload &&
payload.llmProvider &&
typeof payload.llmProvider === "object"
? (payload.llmProvider as { id?: unknown })
: null;
const nextProviderId =
typeof nextProvider?.id === "string"
? nextProvider.id
: (provider?.id ?? null);
if (!nextProviderId) {
throw new Error(
"The provider was saved, but no provider id was returned.",View on GitHub (pinned to 2b7df46e8a)
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.
Example fix
// before
if (!response.ok) {
throw getRequestError(payload, response, `Failed to save provider (${response.status}).`);
}
// after
const apiKey = input.apiKey.trim();
if (apiKey.length === 0) throw new Error("API key is required.");
if (!response.ok) {
throw getRequestError(payload, response, `Failed to save provider (${response.status}).`);
} Defensive patterns
Strategy: validation
Validate before calling
// before saveProvider
const apiKey = form.apiKey.trim();
if (apiKey.length === 0) throw new Error("API key is required.");
try { new URL(form.baseUrl); } catch { throw new Error("Base URL must be a valid URL."); }
if (form.name.trim().length === 0) throw new Error("Name is required.");
const duplicate = providers.some((p) => p.name === form.name.trim() && p.id !== form.id);
if (duplicate) throw new Error("A provider with this name already exists."); Type guard
function isReauthError(e: unknown): e is ReauthRequiredError {
return e instanceof ReauthRequiredError;
} Try / catch
try {
await saveProvider(orgSlug, payload);
} catch (error) {
if (isReauthError(error)) { startReauth(); return; }
if (/\(409\)/.test(error.message)) { setFieldError("name", "Name already in use."); return; }
setFormError(error.message);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to delete provider (${response.status}).
- Failed to connect GitHub repository (${response.status}).
- Failed to apply GitHub discovery (${response.status}).
- Failed to disconnect integration (${response.status}).
- Failed to update auto-import (${response.status}).
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/c4d5eee99291f206.
Report an issue: GitHub.