{"record":{"id":"690d7f6ba8ecc468","repo":"moeru-ai/airi","slug":"failed-to-add-provider","errorCode":null,"errorMessage":"Failed to add provider","messagePattern":"Failed to add provider","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-ui/src/services/inference-service-providers.ts","lineNumber":164,"sourceCode":"      providers[provider.id] = provider\n    }\n    return providers\n  }\n\n  async function createRemote(client: InferenceServiceProvidersRemoteClient, provider: InferenceServiceProvider, options?: InferenceServiceProviderServiceOptions): Promise<InferenceServiceProvider> {\n    options?.abortSignal?.throwIfAborted()\n    const res = await client.api.v1.providers.$post({\n      json: {\n        id: provider.id,\n        definitionId: provider.definitionId,\n        name: getDefinedProvider(provider.definitionId)?.name ?? provider.definitionId,\n        config: provider.config,\n        validated: provider.status === 'configured',\n        validationBypassed: provider.status === 'bypassed',\n      },\n    }, requestOptions(options))\n    if (!res.ok)\n      throw new Error('Failed to add provider')\n\n    const item = await res.json()\n    options?.abortSignal?.throwIfAborted()\n    return normalize(item)\n  }\n\n  async function deleteRemote(client: InferenceServiceProvidersRemoteClient, providerId: string, options?: InferenceServiceProviderServiceOptions): Promise<void> {\n    options?.abortSignal?.throwIfAborted()\n    const res = await client.api.v1.providers[':id'].$delete({\n      param: { id: providerId },\n    }, requestOptions(options))\n    if (!res.ok)\n      throw new Error('Failed to remove provider')\n    options?.abortSignal?.throwIfAborted()\n  }\n\n  async function patchConfigRemote(\n    client: InferenceServiceProvidersRemoteClient,","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/moeru-ai/airi/blob/0616eabd5ba89c7bcef0eb1da84694b9c285c573/packages/stage-ui/src/services/inference-service-providers.ts#L146-L182","documentation":"Thrown by createRemote (add provider) when POST /api/v1/providers returns non-2xx. The request body carries id, definitionId, resolved name, config, and derived validated/validationBypassed flags; the server rejects it on duplicate ids, unknown definitionIds, schema-invalid config, or auth failure. The status code is swallowed by the res.ok check.","triggerScenarios":"Adding a provider whose nanoid id already exists server-side (e.g. after a restore/sync duplicated records); posting a definitionId the server does not know; config failing server-side validation, in particular when status 'configured' sends validated: true but required credentials are missing; expired auth (401).","commonSituations":"Restoring a provider list from backup or another device so ids collide; client and server disagree on supported provider definitions after a partial upgrade; adding a provider while its config form is half-filled and it was marked configured anyway.","solutions":["Check the HTTP status and server response body to see which validation failed.","If the id collides, delete the existing remote provider first (deleteRemote) or generate a fresh id before posting.","Confirm the definitionId is known to the server, not just the client.","Only mark status 'configured' after the config actually validates, or use 'bypassed' deliberately.","Re-authenticate if 401/403."],"exampleFix":"// before\nawait providersService.createRemote(client, provider)\n\n// after\n// avoid duplicate-id rejections when re-adding a restored provider\nawait providersService.deleteRemote(client, provider.id).catch(() => {})\nconst created = await providersService.createRemote(client, {\n  ...provider,\n  id: nanoid(),\n})","handlingStrategy":"try-catch","validationCode":"// Avoid duplicate-id rejections: confirm the id is free before posting\nconst existing = await providersService.fetchRemote(client, { abortSignal })\nif (existing[provider.id])\n  provider = { ...provider, id: nanoid() }\nawait providersService.createRemote(client, provider, { abortSignal })","typeGuard":null,"tryCatchPattern":"try {\n  const created = await providersService.createRemote(client, provider, { abortSignal })\n}\ncatch (error) {\n  // server rejected the payload: surface the validation problem, keep the form open\n  toast.error(errorMessageFrom(error) ?? 'Failed to add provider')\n  // optionally clear a colliding id and let the user retry\n}","preventionTips":["Generate a fresh id for every create instead of reusing ids from restores/exports.","Only mark a provider 'configured' after its config validates; otherwise save as 'bypassed'.","Confirm the server knows the definitionId before adding.","Keep the add-provider form state intact on failure so users can correct and resubmit."],"tags":["http","api-client","providers","validation","remote"],"backgroundTag":"http-error-status","analyzedSha":"0616eabd5ba89c7bcef0eb1da84694b9c285c573","analyzedAt":"2026-08-18T17:29:58.153Z","contentChangedAt":"2026-08-18T17:29:58.153Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}