CherryHQ/cherry-studio · error · Error
Provider extension "${providerId}" not registered
Error message
Provider extension "${providerId}" not registered What it means
createExecutor checks extensionRegistry.has(providerId) before doing anything else; if the id is not registered (by name or alias) it throws immediately, before attempting provider creation. This is the top-level guard for all convenience factories (streamText, generateText, generateImage, embedMany, rerank).
Source
Thrown at packages/aiCore/src/core/runtime/index.ts:36
} from './types'
// === 便捷工厂函数 ===
import { type AiPlugin } from '../plugins'
import { extensionRegistry } from '../providers'
import { type CoreProviderSettingsMap, type StringKeys } from '../providers/types'
import { RuntimeExecutor } from './executor'
/**
* 创建运行时执行器 - 支持类型安全的已知provider
* 自动确保 provider 已初始化
*/
export async function createExecutor<
TSettingsMap extends Record<string, any> = CoreProviderSettingsMap,
T extends StringKeys<TSettingsMap> = StringKeys<TSettingsMap>
>(providerId: T, options: TSettingsMap[T], plugins?: AiPlugin[]): Promise<RuntimeExecutor<TSettingsMap, T>> {
if (!extensionRegistry.has(providerId)) {
throw new Error(`Provider extension "${providerId}" not registered`)
}
const provider = await extensionRegistry.createProvider(providerId, options || {})
// Extract model resolver from variant's resolveModel declaration (type-safe at extension level)
const resolver = extensionRegistry.getModelResolver(providerId as string)
const modelResolver = resolver ? (modelId: string) => resolver(provider, modelId) : undefined
return RuntimeExecutor.create<TSettingsMap, T>(providerId, provider, options, plugins, modelResolver)
}
/**
* Resolves a language model for any provider with its middleware applied.
*
* When `plugins` are provided, middleware contributed through
* `configureContext` is applied to the returned model. This lets independently
* resolved models, such as retry fallbacks, retain their model-specific
* adapters.View on GitHub (pinned to 726446b54c)
Solutions
- Check extensionRegistry.has(providerId) (or hasProviderConfig) before calling.
- Ensure the initialization module is imported so coreExtensions are registered.
- Register custom extensions before use; correct the id or use a known alias.
Example fix
// before
await streamText('opena1', { apiKey }, { model: 'gpt-4o', prompt: 'hi' })
// after
import '@cherrystudio/ai-core/provider' // ensures registration
await streamText('openai', { apiKey }, { model: 'gpt-4o', prompt: 'hi' }) Defensive patterns
Strategy: validation
Validate before calling
import { extensionRegistry } from '@cherrystudio/ai-core/provider'
if (!extensionRegistry.has(providerId)) {
throw new Error(`Provider "${providerId}" not registered. Available: ${extensionRegistry.getAllProviderIds().join(', ')}`)
}
await createExecutor(providerId, options) Prevention
- Import the provider initialization module at app entry so coreExtensions register.
- Guard against tree-shaking removing the registration side-effect.
- Register custom extensions at bootstrap before any factory call.
When it happens
Trigger: Calling createExecutor (or streamText/generateText/generateImage/embedMany/rerank factory) with a providerId that was never registered and is not an alias — e.g. a typo or a custom provider registered later.
Common situations: Typo in provider id; custom extension not yet registered; calling before the initialization module (which runs extensionRegistry.registerAll(coreExtensions)) has loaded; tree-shaking stripping the init side-effect.
Related errors
- Private key must be a non-empty string
- MODEL_RESOLUTION_FAILED
- [theme-contract] theme-input.css declares unregistered runti
- [theme-contract] product variable ${token} overlaps the offi
- [theme-contract] Tailwind product color ${token} is missing
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/b3b32c37ddf9960d.
Report an issue: GitHub.