moeru-ai/airi · error · Error

Failed to fetch providers

Error message

Failed to fetch providers

What it means

Thrown by fetchRemote in the inference-service-providers service when GET /api/v1/providers (typed RPC client.api.v1.providers.$get) returns a non-2xx status. The service discards the status code, so auth failures, missing backend, and server errors all surface as this single message. It is the entry point for hydrating the remote provider list, so failures here usually blank the whole providers UI.

Solutions

  1. Check the actual HTTP status via the network tab or by including res.status in the thrown error.
  2. Start/verify the hosted backend stack and edge routing.
  3. Re-authenticate if the status is 401/403.
  4. Match client and server versions so the /api/v1/providers route exists and its response parses.
  5. Fall back to local provider definitions while remote is unavailable, surfacing a retry action in the UI.

Example fix

// before
const res = await client.api.v1.providers.$get(undefined, requestOptions(options))
if (!res.ok)
  throw new Error('Failed to fetch providers')

// after
const res = await client.api.v1.providers.$get(undefined, requestOptions(options))
if (!res.ok)
  throw new Error(`Failed to fetch providers (HTTP ${res.status})`)
Defensive patterns

Strategy: retry

Validate before calling

// Simple reachability check before hydrating providers
await fetch(apiBaseUrl, { method: 'HEAD', signal: abortSignal })
const providers = await providersService.fetchRemote(client, { abortSignal })

Try / catch

let providers: InferenceServiceProviders | undefined
for (let attempt = 0; attempt < 3 && !providers; attempt++) {
  try {
    providers = await providersService.fetchRemote(client, { abortSignal })
  }
  catch (error) {
    if (abortSignal?.aborted || attempt === 2)
      throw error
    await delay(500 * 2 ** attempt) // backoff before retry
  }
}

Prevention

When it happens

Trigger: Fetching providers when the hosted API is down or unreachable (5xx/network proxy errors); auth session expired (401) so the route rejects; backend deployed without the providers route or with a schema mismatch after a partial upgrade (404/500).

Common situations: App configured for the remote/server mode while docker-compose stack is stopped; token expired after long idle; server version older than the client expecting newer /api/v1/providers contract.

Related errors


AI-assisted analysis of moeru-ai/airi@0616eabd5b (2026-08-18). Data as JSON: /api/errors/a15c2c3042ba2185. Report an issue: GitHub.

Appendix: source

Thrown at packages/stage-ui/src/services/inference-service-providers.ts:138

    if (item.validated)
      status = 'configured'
    else if (item.validationBypassed)
      status = 'bypassed'

    return {
      id: item.id,
      definitionId: item.definitionId,
      config: item.config,
      status,
      configuredBy: getDefinedProvider(item.definitionId)?.configuredBy ?? 'user',
    }
  }

  async function fetchRemote(client: InferenceServiceProvidersRemoteClient, options?: InferenceServiceProviderServiceOptions): Promise<InferenceServiceProviders> {
    options?.abortSignal?.throwIfAborted()
    const res = await client.api.v1.providers.$get(undefined, requestOptions(options))
    if (!res.ok)
      throw new Error('Failed to fetch providers')

    const data = await res.json() as unknown[]
    options?.abortSignal?.throwIfAborted()

    const providers: InferenceServiceProviders = {}
    for (const item of data) {
      const provider = normalize(item)
      providers[provider.id] = provider
    }
    return providers
  }

  async function createRemote(client: InferenceServiceProvidersRemoteClient, provider: InferenceServiceProvider, options?: InferenceServiceProviderServiceOptions): Promise<InferenceServiceProvider> {
    options?.abortSignal?.throwIfAborted()
    const res = await client.api.v1.providers.$post({
      json: {
        id: provider.id,
        definitionId: provider.definitionId,

View on GitHub (pinned to 0616eabd5b)