{"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":162,"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":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-ui/src/services/inference-service-providers.ts#L144-L180","documentation":"Thrown by InferenceServiceProvidersService.createRemote when POST /v1/providers returns non-ok. The service posts a payload including id, definitionId, name, config, validated, and validationBypassed, then normalizes the response. Failure aborts before normalize, so no provider is added.","triggerScenarios":"client.api.v1.providers.$post({ json: {...} }) resolves with ok=false. Typical: 400 (invalid config / unknown definitionId server-side), 401/403 (not authenticated), 409 (duplicate provider id), 422 (config validation failed on the backend), 500 (server).","commonSituations":"Adding a provider with an invalid apiKey in config that fails server-side validation; duplicate id collision; session expired; backend provider validation stricter than client; definitionId not recognized by the server.","solutions":["Validate the provider config client-side before posting (required fields like apiKey for the definition).","Confirm definitionId exists both client-side and server-side.","Re-authenticate on 401/403; on 409 pick a unique id.","Capture res.status and server validation detail to surface config errors to the settings form."],"exampleFix":"// before\nif (!res.ok)\n  throw new Error('Failed to add provider')\n\n// after\nif (!res.ok) {\n  const detail = await res.json().catch(() => null)\n  throw new AddProviderError(`Failed to add provider (status ${res.status})`, detail)\n}","handlingStrategy":"validation","validationCode":"import { getDefinedProvider } from '../../libs/providers/providers'\n\nfunction validateNewProvider(provider: { definitionId: string, config: Record<string, unknown> }): string[] {\n  const errors: string[] = []\n  if (!getDefinedProvider(provider.definitionId))\n    errors.push(`Unknown provider definition: ${provider.definitionId}`)\n  // definition-specific required-field checks (e.g. apiKey) go here\n  return errors\n}\n\nconst issues = validateNewProvider(provider)\nif (issues.length)\n  throw new Error('Invalid provider: ' + issues.join(', '))\nawait createRemote(client, provider)","typeGuard":"function isRegisteredProviderDefinition(definitionId: string): boolean {\n  return !!getDefinedProvider(definitionId)\n}","tryCatchPattern":"try {\n  return await createRemote(client, provider)\n}\ncatch (error) {\n  // Patch service to expose res.status + body; map 400/422 to config field errors, 409 to duplicate id.\n  // On 401/403 re-authenticate.\n  throw error\n}","preventionTips":["Validate provider config client-side (including definition-specific required fields like apiKey) before posting.","Confirm definitionId exists both client- and server-side.","Embed res.status and server validation detail in the service error for the settings form."],"tags":["network","http","providers","api","validation","auth"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}