upstash/context7 · error · Error
Failed to fetch user info
Error message
Failed to fetch user info
What it means
Thrown by fetchWhoami() in the CLI auth command when the GET to /api/dashboard/whoami returns a non-2xx status. The CLI sends the stored access token as a Bearer header to verify the session and load the user's teamspace; any failure here aborts that lookup. The thrown Error carries no status code, so the original HTTP status is lost by the time it reaches a caller.
Source
Thrown at packages/cli/src/commands/auth.ts:262
}
}
interface WhoamiResponse {
success: boolean;
name: string | null;
email: string | null;
teamspace: { id: string; name: string } | null;
}
async function fetchWhoami(accessToken: string): Promise<WhoamiResponse> {
const response = await fetch(`${getBaseUrl()}/api/dashboard/whoami`, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) {
throw new Error("Failed to fetch user info");
}
return (await response.json()) as WhoamiResponse;
}
View on GitHub (pinned to ca15df0443)
Solutions
- Re-run `auth login` (or the CLI's refresh command) to mint a fresh access token, then retry.
- Verify getBaseUrl() resolves to the correct dashboard host (check the configured base URL / env override).
- If the caller needs the real cause, reproduce the request with curl using the same Bearer token to read the actual status code and body.
- For transient 5xx, retry the whoami call after a short delay rather than forcing a full re-login.
Example fix
// before
if (!response.ok) {
throw new Error("Failed to fetch user info");
}
// after — preserve status so callers can branch on 401 vs 5xx
if (!response.ok) {
const detail = await response.text().catch(() => "");
const err = new Error(`Failed to fetch user info (HTTP ${response.status})`);
(err as any).status = response.status;
(err as any).body = detail.slice(0, 200);
throw err;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Validate the token shape before calling fetchWhoami.
function hasUsableToken(token: unknown): token is string {
return typeof token === "string" && token.length > 0 && token.split(".").length >= 2;
}
if (!hasUsableToken(accessToken)) {
throw new Error("No usable access token — run `auth login` first.");
}
const me = await fetchWhoami(accessToken); Type guard
function isWhoamiResponse(v: unknown): v is WhoamiResponse {
return (
typeof v === "object" && v !== null &&
typeof (v as any).success === "boolean"
);
} Try / catch
try {
const me = await fetchWhoami(accessToken);
} catch (e) {
// fetchWhoami erases the status; treat any failure as "session invalid"
// and prompt re-login rather than looping.
await reauthenticate();
return;
} Prevention
- Refresh the access token proactively before its expiry rather than waiting for whoami to fail.
- Wrap whoami in a single retry for transient 5xx before forcing re-login.
- Patch fetchWhoami to attach response.status to the error so callers can distinguish 401 from 5xx.
When it happens
Trigger: A whoami request returns 401 (access token expired or revoked), 403 (token valid but not authorized for dashboard), 404/000 (getBaseUrl() points at the wrong host so the path does not resolve), or any 5xx from the dashboard backend. Note: a low-level network failure (DNS, TLS) is NOT caught here — fetch() rejects first and a different error propagates.
Common situations: Long-running CLI session whose access token expired since login; user pointed the CLI at a stale/wrong base URL; dashboard backend temporarily down during a deploy; token revoked from another device.
Related errors
- ${fallback} (HTTP ${response.status} from ${response.url}):
- no files
- Could not reach ${url}: ${detail}${code ? ` (${code})` : ""}
- Device token poll failed
- API key is required. Pass it in the config or set CONTEXT7_A
AI-assisted analysis of upstash/context7@ca15df0443 (2026-08-12).
Data as JSON: /api/errors/f85bbe67ca9b9329.
Report an issue: GitHub.