windmill-labs/windmill · error
API key or resource path is required
Error message
API key or resource path is required
What it means
testKey() validates an AI provider credential by making a small test completion through the AI proxy. It requires at least one authentication means: an API key (sent as X-API-Key) or a resource path (sent as X-Resource-Path, used for Azure-like providers). If both are missing/empty the call cannot authenticate, so it throws immediately before any network request.
Source
Thrown at frontend/src/lib/components/copilot/lib.ts:583
export async function testKey({
apiKey,
workspace,
resourcePath,
model,
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: {View on GitHub (pinned to e474e8803c)
Solutions
- Enter an API key in the provider settings before clicking Test.
- For providers that authenticate by resource path (e.g. Azure), fill in the resource path instead of the key.
- Check that the settings form actually binds the apiKey/resourcePath inputs to the object passed to testKey.
- Confirm the stored workspace AI config retains the key (not stripped by sanitization before the call).
Example fix
// before
await testKey({ aiProvider: 'openai', model, messages, abortController })
// after
if (!apiKey && !resourcePath) { alert('Enter an API key first'); return }
await testKey({ aiProvider: 'openai', apiKey, model, messages, abortController }) Defensive patterns
Strategy: validation
Validate before calling
if (!apiKey?.trim() && !resourcePath?.trim()) {
showToast('Enter an API key or resource path before testing')
return
} Type guard
function hasCredential(opts: { apiKey?: string; resourcePath?: string }): boolean {
return Boolean(opts.apiKey?.trim() || opts.resourcePath?.trim())
} Try / catch
try {
await testKey({ aiProvider, apiKey, resourcePath, model, messages, abortController })
} catch (e) {
if (e.message === 'API key or resource path is required') {
showToast('A credential is required to test this provider')
} else throw e
} Prevention
- Disable the Test button until the key/resource-path field is non-empty.
- Persist credentials before offering the test action.
- Show provider-specific hints (key vs resource path) in the settings form.
When it happens
Trigger: Calling testKey({ apiKey: undefined, resourcePath: undefined, ... }) — e.g. the 'Test' button in the AI settings modal clicked with the key field left blank, or a saved config whose key was never persisted.
Common situations: User saves AI settings without pasting an API key; a provider that needs a resource path (Azure OpenAI / customai) configured with only an empty key field; config object spread losing the apiKey field.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
- Missing a model to test
- Cannot test API key for Custom AI, only resource path is sup
- Invalid AI agent provider configuration: ${errors.join('\n')
- ${label} is invalid: ${formatZodError(result.error)}
- describeDroppedScheduleOptions(dropped)
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/ef9c5ab1484c90f6.
Report an issue: GitHub.