JuliusBrussee/caveman · error
request auth unavailable
Error message
request auth unavailable
What it means
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.
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.
Example fix
// before: routed model with no credentials registered
modelRegistry.register({ id: "my-model", route: "anthropic/claude" });
// after: register the model together with its API key/auth headers
modelRegistry.register({
id: "my-model",
route: "anthropic/claude",
apiKey: process.env.ANTHROPIC_API_KEY,
authHeaders: { "x-api-key": process.env.ANTHROPIC_API_KEY },
}); Defensive patterns
Strategy: try-catch
Validate before calling
// before opening the gate, confirm the model resolves with credentials
const probe = await ctx.modelRegistry.getApiKeyAndHeaders(model);
if (!probe.ok) throw new Error(`no credentials resolvable for model ${model.id}; configure an API key or run auth login`); Type guard
function hasResolvedAuth(a: { ok: boolean; headers?: Record<string, string> }): a is { ok: true; headers: Record<string, string> } {
return a.ok === true && typeof a.headers === "object";
} Try / catch
try {
await provider.apply(...);
} catch (e) {
if (e instanceof Error && e.message === "request auth unavailable") {
// prompt/trigger re-auth (OAuth login) or configure the provider API key
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- awscreds: returned incomplete credentials
- caveman agent: multiple provider credentials found; set…
- caveman-code: no supported provider credential found; set…
- objectstore: access key and secret key are required
- aes cipher
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/c808d10869181d5b.
Report an issue: GitHub.
Appendix: source
Thrown at packages/pi-extension/src/provider.ts:95
// recover the effective cache option or distinguish another extension's
// removal, so leave this specific endpoint direct. Responses is unaffected.
const compatibilityIssue = model.api === "openai-completions" && original.includes("api.openai.com")
? "Pi cannot preserve this OpenAI Chat endpoint's prompt cache keys through routing"
: undefined;
let headerIssue: string | undefined;
let oauth = true;
try {
oauth = ctx.modelRegistry.isUsingOAuth(model);
} catch {
// Cannot determine the auth kind ⇒ treat as OAuth and refuse (uncertain ⇒ direct).
}
if (!oauth && route && !compatibilityIssue) {
try {
// Pi adds configured provider/auth headers during request preparation;
// they need not appear on model.headers. Use its public resolver and
// discard the API key. Never log values or replace the auth handler.
const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
if (!auth.ok) throw new Error("request auth unavailable");
const { headers } = auth;
const published = {
...(this.compatUpstreams ? { compat_upstreams: this.compatUpstreams } : {}),
...(this.compatForwardHeaders ? { compat_forward_headers: this.compatForwardHeaders } : {}),
};
const missingHeaders = [...new Set([
...unforwardedProviderHeaders(model.api, model.provider, model.headers, published),
...unforwardedProviderHeaders(model.api, model.provider, headers, published),
])].sort();
if (missingHeaders.length) {
const remedy = missingHeaders.some(name => ["authorization", "x-api-key", "x-goog-api-key"].includes(name.toLowerCase()))
? "the proxy cannot preserve this authentication override; keep the provider direct"
: `configure compat.${model.provider}.forward_headers`;
headerIssue = `provider headers ${missingHeaders.join(", ")} are not forwarded; ${remedy}`;
}
if (!headerIssue) {
let sessionId: string | undefined;
try { sessionId = ctx.sessionManager.getSessionId(); } catch { /* unknown session affinity stays direct */ }View on GitHub (pinned to 3ee70a1026)