{"record":{"id":"0d6e63ce2f7c2587","repo":"alibaba/page-agent","slug":"auth-error","errorCode":"AUTH_ERROR","errorMessage":"Authentication failed: ${errorMessage}","messagePattern":"Authentication failed: (.+?)","errorType":"http","errorClass":"InvokeError","httpStatus":401,"severity":"critical","filePath":"packages/llms/src/OpenAIClient.ts","lineNumber":102,"sourceCode":"\t\t\t})\n\t\t} catch (error: unknown) {\n\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\tconsole.error(error)\n\t\t\tthrow new InvokeError(InvokeErrorTypes.NETWORK_ERROR, 'Network request failed', error)\n\t\t}\n\n\t\t// 3. Handle HTTP errors\n\t\tif (!response.ok) {\n\t\t\tlet errorData: any\n\t\t\ttry {\n\t\t\t\terrorData = await response.json()\n\t\t\t} catch (error) {\n\t\t\t\tif ((error as any)?.name === 'AbortError') throw error\n\t\t\t}\n\t\t\tconst errorMessage = errorData?.error?.message || response.statusText\n\n\t\t\tif (response.status === 401 || response.status === 403) {\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.AUTH_ERROR,\n\t\t\t\t\t`Authentication failed: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (response.status === 429) {\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.RATE_LIMIT,\n\t\t\t\t\t`Rate limit exceeded: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)\n\t\t\t}\n\t\t\tif (response.status >= 500) {\n\t\t\t\tthrow new InvokeError(\n\t\t\t\t\tInvokeErrorTypes.SERVER_ERROR,\n\t\t\t\t\t`Server error: ${errorMessage}`,\n\t\t\t\t\terrorData\n\t\t\t\t)","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/alibaba/page-agent/blob/d02db1ee7c41f5315beda88bab2fe935c580f662/packages/llms/src/OpenAIClient.ts#L84-L120","documentation":"The endpoint returned HTTP 401 or 403, meaning the API key is missing, invalid, expired, or lacks permission for the requested resource/model. The message embeds the provider's error message from the response body (or statusText as fallback), and the parsed error body is attached as details.","triggerScenarios":"invoke() call where the server responds 401 (bad/missing API key) or 403 (key valid but forbidden — model not entitled, org restricted, or region blocked). Common with OpenAI, Azure (wrong deployment/key header), Gemini OpenAI-compat endpoints with an invalid key.","commonSituations":"API key env var not set or pasted with whitespace/quotes; using an OpenAI key against an Azure or Gemini baseURL; free-tier key requesting a paid model; expired or revoked token; wrong apiKeyHeader configuration for a compatible provider.","solutions":["Verify the API key is set, non-empty, and copied exactly (no quotes/newlines)","Confirm the key matches the provider implied by baseURL — OpenAI keys don't work on Azure/Gemini/other compatible endpoints","For Azure-style endpoints, ensure the auth header and deployment name required by that provider are configured (via transformRequestHeaders/requestBody)","Test the key directly: curl -H \"Authorization: Bearer $KEY\" <baseURL>/models","If 403 on a specific model, switch to a model your account is entitled to"],"exampleFix":"// before\nconst client = new OpenAIClient({ baseURL: 'https://api.openai.com/v1', apiKey: undefined })\n\n// after\nconst client = new OpenAIClient({\n  baseURL: 'https://api.openai.com/v1',\n  apiKey: process.env.OPENAI_API_KEY!, // ensure it is loaded and trimmed\n})","handlingStrategy":"try-catch","validationCode":"if (!cfg.apiKey || cfg.apiKey.trim().length < 20) {\n  throw new Error('API key missing or suspiciously short')\n}","typeGuard":"const isAuthError = (e: unknown): e is InvokeError =>\n  e instanceof InvokeError && e.code === 'AUTH_ERROR'","tryCatchPattern":"try {\n  await client.invoke(req)\n} catch (e) {\n  if (isAuthError(e)) {\n    // keys rarely heal — surface to user, do not retry\n    throw new Error(`Check your API key: ${e.message}`)\n  }\n  throw e\n}","preventionTips":["Fail fast on missing/empty apiKey at construction time","Load keys from env/secret manager, never hardcode or paste with whitespace","Match the key to the provider implied by baseURL"],"tags":["auth","http-401","http-403","openai-client"],"backgroundTag":"invalid-api-key","analyzedSha":"d02db1ee7c41f5315beda88bab2fe935c580f662","analyzedAt":"2026-08-28T19:39:48.634Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}