{"record":{"id":"ef9c5ab1484c90f6","repo":"windmill-labs/windmill","slug":"api-key-or-resource-path-is-required","errorCode":null,"errorMessage":"API key or resource path is required","messagePattern":"API key or resource path is required","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/lib.ts","lineNumber":583,"sourceCode":"export async function testKey({\n\tapiKey,\n\tworkspace,\n\tresourcePath,\n\tmodel,\n\tabortController,\n\tmessages,\n\taiProvider\n}: {\n\tapiKey?: string\n\tworkspace?: string\n\tresourcePath?: string\n\tmodel: string | undefined\n\tmessages: ChatCompletionMessageParam[]\n\tabortController: AbortController\n\taiProvider: AIProvider\n}) {\n\tif (!apiKey && !resourcePath) {\n\t\tthrow new Error('API key or resource path is required')\n\t}\n\tconst modelToTest = model ?? AI_PROVIDERS[aiProvider].defaultModels[0]\n\n\tif (!modelToTest) {\n\t\tthrow new Error('Missing a model to test')\n\t}\n\n\t// getNonStreamingCompletion routes Anthropic-Messages-API models (native\n\t// Anthropic and Claude on Azure Foundry) through the Anthropic SDK and\n\t// everything else through OpenAI chat completions, so the test exercises the\n\t// same request shape the feature actually sends. The cap keeps max_tokens\n\t// under the Anthropic SDK's non-streaming pre-flight limit (~21k tokens),\n\t// which would otherwise reject the request before it is sent.\n\tawait getNonStreamingCompletion(messages, abortController, {\n\t\tapiKey,\n\t\tworkspace,\n\t\tresourcePath,\n\t\tforceModelProvider: {","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/lib.ts#L565-L601","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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)."],"exampleFix":"// before\nawait testKey({ aiProvider: 'openai', model, messages, abortController })\n// after\nif (!apiKey && !resourcePath) { alert('Enter an API key first'); return }\nawait testKey({ aiProvider: 'openai', apiKey, model, messages, abortController })","handlingStrategy":"validation","validationCode":"if (!apiKey?.trim() && !resourcePath?.trim()) {\n  showToast('Enter an API key or resource path before testing')\n  return\n}","typeGuard":"function hasCredential(opts: { apiKey?: string; resourcePath?: string }): boolean {\n  return Boolean(opts.apiKey?.trim() || opts.resourcePath?.trim())\n}","tryCatchPattern":"try {\n  await testKey({ aiProvider, apiKey, resourcePath, model, messages, abortController })\n} catch (e) {\n  if (e.message === 'API key or resource path is required') {\n    showToast('A credential is required to test this provider')\n  } else throw e\n}","preventionTips":["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."],"tags":["validation","api-key","configuration","copilot"],"backgroundTag":"missing-api-key","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}