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
- Select a provider whose capabilities include chat/generation for the model in question.
- Check findProviderDefinition(providerId).capabilities.chat before calling; show a settings error instead.
- Fix module configuration that points at a non-generation provider id.
- 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
- Filter provider pickers to providers with chat capability when configuring chat models.
- Re-validate provider assignments after provider type changes or upgrades.
- Distinguish provider ids by kind (chat/embeddings/speech) in stored configuration.
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
- Failed to add provider
- Failed to fetch providers
- Failed to remove provider
- Failed to update provider config
- [llm] Auto-disabling content-part arrays for
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-providerView on GitHub (pinned to 438a067dde)