{"record":{"id":"c808d10869181d5b","repo":"JuliusBrussee/caveman","slug":"request-auth-unavailable","errorCode":null,"errorMessage":"request auth unavailable","messagePattern":"request auth unavailable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/pi-extension/src/provider.ts","lineNumber":95,"sourceCode":"    // recover the effective cache option or distinguish another extension's\n    // removal, so leave this specific endpoint direct. Responses is unaffected.\n    const compatibilityIssue = model.api === \"openai-completions\" && original.includes(\"api.openai.com\")\n      ? \"Pi cannot preserve this OpenAI Chat endpoint's prompt cache keys through routing\"\n      : undefined;\n    let headerIssue: string | undefined;\n    let oauth = true;\n    try {\n      oauth = ctx.modelRegistry.isUsingOAuth(model);\n    } catch {\n      // Cannot determine the auth kind ⇒ treat as OAuth and refuse (uncertain ⇒ direct).\n    }\n    if (!oauth && route && !compatibilityIssue) {\n      try {\n        // Pi adds configured provider/auth headers during request preparation;\n        // they need not appear on model.headers. Use its public resolver and\n        // discard the API key. Never log values or replace the auth handler.\n        const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);\n        if (!auth.ok) throw new Error(\"request auth unavailable\");\n        const { headers } = auth;\n        const published = {\n          ...(this.compatUpstreams ? { compat_upstreams: this.compatUpstreams } : {}),\n          ...(this.compatForwardHeaders ? { compat_forward_headers: this.compatForwardHeaders } : {}),\n        };\n        const missingHeaders = [...new Set([\n          ...unforwardedProviderHeaders(model.api, model.provider, model.headers, published),\n          ...unforwardedProviderHeaders(model.api, model.provider, headers, published),\n        ])].sort();\n        if (missingHeaders.length) {\n          const remedy = missingHeaders.some(name => [\"authorization\", \"x-api-key\", \"x-goog-api-key\"].includes(name.toLowerCase()))\n            ? \"the proxy cannot preserve this authentication override; keep the provider direct\"\n            : `configure compat.${model.provider}.forward_headers`;\n          headerIssue = `provider headers ${missingHeaders.join(\", \")} are not forwarded; ${remedy}`;\n        }\n        if (!headerIssue) {\n          let sessionId: string | undefined;\n          try { sessionId = ctx.sessionManager.getSessionId(); } catch { /* unknown session affinity stays direct */ }","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/pi-extension/src/provider.ts#L77-L113","documentation":"Thrown in the provider's apply() when the model registry's getApiKeyAndHeaders(model) resolver fails to produce auth credentials (returns ok:false) for a routed model. The library requires a valid auth resolver result before it will attach Pi-configured provider/auth headers to outgoing requests; without them the request would be unauthenticated, so it aborts. This is a runtime configuration/credential availability failure, not a network error.","triggerScenarios":"apply() is invoked from openGate for a model that (a) has no OAuth token available, (b) has a route configured, (c) does not have a compatibility issue flag set, and (d) whose ctx.modelRegistry.getApiKeyAndHeaders(model) call returns { ok: false } — i.e. no API key/headers could be resolved for that model.","commonSituations":"Provider configured with a route but no API key or OAuth login for the model; credentials removed or expired from the model registry; model ID mistyped so no registered provider matches it; running in an environment where the auth store is unavailable (CI without prior login).","solutions":["Run the provider's auth/login flow (OAuth) or configure an API key for the routed model so getApiKeyAndHeaders succeeds.","Verify the model ID resolves to a registered provider in ctx.modelRegistry (check provider config/JSON).","Check that credentials were not deleted or expired; re-authenticate.","If the route is only needed conditionally, remove or fix the route so the !route branch is taken, or set the compatibility flag if applicable."],"exampleFix":"// before: routed model with no credentials registered\nmodelRegistry.register({ id: \"my-model\", route: \"anthropic/claude\" });\n\n// after: register the model together with its API key/auth headers\nmodelRegistry.register({\n  id: \"my-model\",\n  route: \"anthropic/claude\",\n  apiKey: process.env.ANTHROPIC_API_KEY,\n  authHeaders: { \"x-api-key\": process.env.ANTHROPIC_API_KEY },\n});","handlingStrategy":"try-catch","validationCode":"// before opening the gate, confirm the model resolves with credentials\nconst probe = await ctx.modelRegistry.getApiKeyAndHeaders(model);\nif (!probe.ok) throw new Error(`no credentials resolvable for model ${model.id}; configure an API key or run auth login`);","typeGuard":"function hasResolvedAuth(a: { ok: boolean; headers?: Record<string, string> }): a is { ok: true; headers: Record<string, string> } {\n  return a.ok === true && typeof a.headers === \"object\";\n}","tryCatchPattern":"try {\n  await provider.apply(...);\n} catch (e) {\n  if (e instanceof Error && e.message === \"request auth unavailable\") {\n    // prompt/trigger re-auth (OAuth login) or configure the provider API key\n  } else throw e;\n}","preventionTips":["Register an API key or complete OAuth login for every model ID you route to.","Validate model IDs against the registry at startup.","In CI, pre-seed credentials rather than relying on an interactive login.","Monitor credential expiry and refresh before tokens lapse."],"tags":["authentication","provider-routing","credentials","configuration"],"backgroundTag":"authentication-required","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}