moeru-ai/airi · error · Error
Failed to resolve chat provider
Error message
Failed to resolve chat provider "${providerId}" What it means
After passing the provider/model precondition, executeSend asks providerStore.getProviderInstance<ChatProvider>(providerId) for a live provider instance and throws when it cannot produce one. This means the id is 'active' in settings but no configured, instantiable provider exists behind it — removed, incompletely configured, or the providers store not yet initialized.
Solutions
- Open provider settings and reconfigure/re-add the chat provider referenced by the error message.
- Re-select the active provider and model in chat settings after changing providers.
- Await providers store initialization before enabling the send action.
- When a provider is removed, clear activeProvider/activeModel so users hit the clearer error 147 instead.
Example fix
// before
await chatStore.send({ sessionId, text })
// after
const provider = providersStore.providers[activeProvider.value]
if (!provider || provider.status !== 'configured') {
toast.info('Configure the active chat provider before sending')
return
}
await chatStore.send({ sessionId, text }) Defensive patterns
Strategy: validation
Validate before calling
const provider = providersStore.providers[activeProvider.value]
if (!provider || (provider.status !== 'configured' && provider.status !== 'bypassed')) {
openProviderSettings()
return
}
await chatStore.send({ sessionId, text }) Type guard
function isResolvableChatProvider(providerId: string | undefined, providers: Record<string, InferenceServiceProvider>): boolean {
if (!providerId) return false
const p = providers[providerId]
return Boolean(p && (p.status === 'configured' || p.status === 'bypassed'))
} Try / catch
try {
await chatStore.send({ sessionId, text })
}
catch (error) {
const message = errorMessageFrom(error) ?? ''
if (message.startsWith('Failed to resolve chat provider')) {
openProviderSettings(message.slice(message.indexOf('"'))) // includes the id
return
}
throw error
} Prevention
- Await providers store initialization before enabling the composer.
- Reset activeProvider/activeModel inside the provider-removal flow.
- Show provider status in chat settings so unconfigured states are visible.
- On startup, cross-check activeProvider against the providers registry and self-heal.
When it happens
Trigger: activeProvider references a provider deleted from settings without resetting chat settings; provider record exists but its config lacks credentials so instantiation returns nothing; send fires before the providers store finished initialization; provider definition no longer registered (paired with error 142's registry).
Common situations: Deleting or resetting a provider in settings then immediately sending from a still-open chat; storage partial restore that kept chat settings but lost provider records; version changes renaming provider definitions.
Related errors
- Failed to initialize speech provider
- Failed to initialize speech provider
- Missing LLM configuration
- No active chat provider or model configured
- Provider credentials for
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-08-28).
Data as JSON: /api/errors/dbaa4eee1225af16.
Report an issue: GitHub.
Appendix: source
Thrown at packages/stage-ui/src/stores/chat.ts:424
chatSession.appendSessionMessage(sessionId, {
role: 'error',
content: errorMessageFrom(error) ?? 'Unknown chat operation failure',
})
}
async function executeSend(payload: ChatSendPayload): Promise<ChatSendResult> {
const providerId = activeProvider.value
const modelId = activeModel.value
if (!providerId || !modelId)
throw new Error('No active chat provider or model configured')
if (!await chatSession.loadSession(payload.sessionId))
throw new Error('Failed to load the target chat session')
const messageCount = chatSession.getSessionMessages(payload.sessionId).length
const chatProvider = await consciousnessStore.getChatProviderInstance(providerId)
if (!chatProvider)
throw new Error(`Failed to resolve chat provider "${providerId}"`)
await runtime.ingest(payload.text, {
model: modelId,
chatProvider,
attachments: payload.attachments,
input: payload.input,
replyToMessageId: payload.replyToMessageId,
toolReferences: payload.tools,
temperature: payload.temperature ?? consciousnessStore.activeTemperature,
topP: payload.topP ?? consciousnessStore.activeTopP,
// Resolve this function after the request reaches the per-session queue.
// The history then contains tool names from every earlier queued turn.
tools: async () => {
const references = collectToolReferences(payload.sessionId, payload.tools)
return llmToolsStore.getToolsByNames(...references.map(tool => tool.name))
},
}, payload.sessionId)
View on GitHub (pinned to 438a067dde)