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

  1. Re-run `auth login` (or the CLI's refresh command) to mint a fresh access token, then retry.
  2. Verify getBaseUrl() resolves to the correct dashboard host (check the configured base URL / env override).
  3. 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.
  4. 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

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


AI-assisted analysis of upstash/context7@ca15df0443 (2026-08-12). Data as JSON: /api/errors/f85bbe67ca9b9329. Report an issue: GitHub.