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

  1. Pass an explicit model argument to testKey() so the default lookup is skipped.
  2. Populate defaultModels[0] for the provider in the AI_PROVIDERS registry.
  3. Verify the aiProvider string matches a registered provider with defaults.
  4. 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

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


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/475f9c2421dd7891. Report an issue: GitHub.