moeru-ai/airi · error · Error

Provider does not support generation

Error message

Provider ${providerId} does not support generation

What it means

getChatProviderInstance wraps getProviderInstance's result with getGenerationProvider; if the resulting provider object has no generation capability, the id refers to a provider that cannot perform chat/generation (e.g. an embedding-only or speech-only provider) and the store throws instead of returning a broken GenerationProvider.

Solutions

  1. Select a provider whose capabilities include chat/generation for the model in question.
  2. Check findProviderDefinition(providerId).capabilities.chat before calling; show a settings error instead.
  3. Fix module configuration that points at a non-generation provider id.
  4. Update the provider definition/adapter if the provider should support generation but its capability metadata is missing.

Example fix

// before
const provider = await getChatProviderInstance('my-embeddings-provider')
// after
const def = findProviderDefinition('my-openai-provider')
if (!def?.capabilities?.chat)
  throw new Error('Select a chat-capable provider')
const provider = await getChatProviderInstance('my-openai-provider')
Defensive patterns

Strategy: validation

Validate before calling

const def = findProviderDefinition(providerId)
if (!def?.capabilities?.chat) {
  throw new Error(`Provider ${providerId} cannot be used for chat`)
}

Try / catch

try {
  const provider = await getChatProviderInstance(providerId)
} catch (e) {
  if (e.message.includes('does not support generation')) ui.showProviderIncompatible(providerId)
  else throw e
}

Prevention

When it happens

Trigger: Calling getChatProviderInstance(providerId) where the provider definition for that id lacks a chat/generation capability — e.g. passing an embedding provider id where a chat provider is expected.

Common situations: Settings state pointing a chat model at a speech/embeddings provider; a provider type that lost chat support after an update; passing the wrong provider id from a module config (like artistry or chat stores).

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17). Data as JSON: /api/errors/82845a29f81b5e72. Report an issue: GitHub.

Appendix: source

Thrown at packages/stage-ui/src/stores/providers/provider.ts:928

      return instance as R
    }
    catch (error) {
      console.error(`Error creating provider instance for ${providerId}:`, error)
      throw error
    }
  }

  /**
   * Passes AIRI chat options to the provider that owns their wire representation.
   * The cached base instance remains unchanged for consumers that do not opt in.
   */
  async function getChatProviderInstance(
    providerId: string,
    options?: ChatRequestOptions,
  ): Promise<GenerationProvider> {
    const provider = getGenerationProvider(await getProviderInstance(providerId))
    if (!provider)
      throw new Error(`Provider ${providerId} does not support generation`)
    const reasoning = findProviderDefinition(providerId)?.capabilities?.chat?.reasoning
    const requestOptions = options && reasoning?.modes.includes(options.reasoning) ? options : undefined
    return { generation: model => provider.generation(model, requestOptions) }
  }

  /** Releases this renderer's transport; each window owns its own instance cache. */
  async function disposeProviderInstance(providerId: string) {
    const instance = providerInstanceCache.get(providerId)?.instance as { dispose?: () => Promise<void> | void } | undefined
    // Remove ownership before awaiting cleanup so a concurrent request cannot reuse it.
    providerInstanceCache.delete(providerId)
    if (instance?.dispose)
      await instance.dispose()
  }

  const availableProvidersMetadata = computedAsync<ProviderMetadata[]>(async () => {
    // Spread-read the overrides synchronously so this re-runs when a
    // server-driven availability flips: computedAsync uses watchEffect, which
    // only tracks reactive reads before the first `await` — the per-provider

View on GitHub (pinned to 438a067dde)