windmill-labs/windmill · error
Missing a model to test
Error message
Missing a model to test
What it means
testKey() falls back to the provider's first default model (AI_PROVIDERS[aiProvider].defaultModels[0]) when no explicit model is passed. If that defaults array is empty or undefined the resolved model is falsy and the test cannot be executed, so it throws 'Missing a model to test'.
Source
Thrown at frontend/src/lib/components/copilot/lib.ts:588
abortController,
messages,
aiProvider
}: {
apiKey?: string
workspace?: string
resourcePath?: string
model: string | undefined
messages: ChatCompletionMessageParam[]
abortController: AbortController
aiProvider: AIProvider
}) {
if (!apiKey && !resourcePath) {
throw new Error('API key or resource path is required')
}
const modelToTest = model ?? AI_PROVIDERS[aiProvider].defaultModels[0]
if (!modelToTest) {
throw new Error('Missing a model to test')
}
// getNonStreamingCompletion routes Anthropic-Messages-API models (native
// Anthropic and Claude on Azure Foundry) through the Anthropic SDK and
// everything else through OpenAI chat completions, so the test exercises the
// same request shape the feature actually sends. The cap keeps max_tokens
// under the Anthropic SDK's non-streaming pre-flight limit (~21k tokens),
// which would otherwise reject the request before it is sent.
await getNonStreamingCompletion(messages, abortController, {
apiKey,
workspace,
resourcePath,
forceModelProvider: {
model: modelToTest,
provider: aiProvider
},
maxTokensCap: METADATA_MAX_TOKENS
})View on GitHub (pinned to e474e8803c)
Solutions
- Pass an explicit model argument to testKey() so the default lookup is skipped.
- Populate defaultModels[0] for the provider in the AI_PROVIDERS registry.
- Verify the aiProvider string matches a registered provider with defaults.
- If testing a customai resource path, supply the model the resource actually serves.
Example fix
// before
await testKey({ aiProvider: 'customai', resourcePath, model: undefined, ... })
// after
await testKey({ aiProvider: 'customai', resourcePath, model: 'gpt-4o', ... }) Defensive patterns
Strategy: validation
Validate before calling
const defaults = AI_PROVIDERS[aiProvider]?.defaultModels ?? []
const modelToTest = model ?? defaults[0]
if (!modelToTest) {
showToast('Select a model — this provider has no default')
return
} Type guard
function hasResolvableModel(provider: AIProvider, model?: string): boolean {
return Boolean(model) || Boolean(AI_PROVIDERS[provider]?.defaultModels?.length)
} Try / catch
try {
await testKey({ aiProvider, apiKey, model, messages, abortController })
} catch (e) {
if (e.message === 'Missing a model to test') {
showToast('Pick a model manually for this provider')
} else throw e
} Prevention
- Always register defaultModels for new providers in AI_PROVIDERS.
- Let the user pick a model explicitly when defaults are absent.
- Validate aiProvider strings against registered keys before calling.
When it happens
Trigger: Calling testKey() with model: undefined for a provider whose AI_PROVIDERS entry has an empty defaultModels array, or an aiProvider key that resolves to an entry without defaults.
Common situations: A newly added/custom provider registered without defaultModels; a typo'd or legacy aiProvider string; a customai resource path configured where no default model list applies.
Related errors
- API key or resource path is required
- Invalid AI agent provider configuration: ${errors.join('\n')
- ${label} is invalid: ${formatZodError(result.error)}
- describeDroppedScheduleOptions(dropped)
- Invalid schedule or timezone: ${formatToolError(error)}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/475f9c2421dd7891.
Report an issue: GitHub.