upstash/context7 · error · Error
${fallback} (HTTP ${response.status} from ${response.url}):
Error message
${fallback} (HTTP ${response.status} from ${response.url}): ${excerpt} What it means
Thrown by oauthRequest() when postForm() succeeds but response.ok is false. describeErrorResponse() first tries to parse the body as an OAuth TokenErrorResponse (error/error_description); if that fails (e.g. HTML from an intercepting proxy) it falls back to '<fallback> (HTTP <status> from <url>): <200-char excerpt>'. The fallback string is supplied per call site (e.g. 'Failed to start device authorization').
Source
Thrown at packages/cli/src/utils/auth.ts:221
return `Could not reach ${url}: ${detail}${code ? ` (${code})` : ""}\n${hint}`;
}
async function postForm(url: string, params: URLSearchParams): Promise<Response> {
try {
return await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: params.toString(),
});
} catch (error) {
throw new Error(describeConnectionError(error, url));
}
}
async function oauthRequest<T>(url: string, params: URLSearchParams, fallback: string): Promise<T> {
const response = await postForm(url, params);
if (!response.ok) {
throw new Error(await describeErrorResponse(response, fallback));
}
return (await response.json()) as T;
}
/** RFC 8628 §3.2 default poll interval when the server omits `interval`. */
export const DEFAULT_DEVICE_POLL_INTERVAL_SECONDS = 5;
export async function startDeviceAuthorization(
baseUrl: string,
clientId: string
): Promise<DeviceAuthorizationResponse> {
// Hostname is shown on the server's verification page so the user can confirm
// that the device they're authorizing matches the one running the CLI
// (RFC 8628 §5.4 phishing resistance). Best-effort.
const params = new URLSearchParams({ client_id: clientId });
try {
const hostname = os.hostname();
if (hostname) params.set("hostname", hostname);View on GitHub (pinned to ca15df0443)
Solutions
- Read the excerpt in the message — if it is HTML, the request is hitting a proxy/gateway, not the auth server; fix the base URL.
- Confirm the OAuth client_id the CLI is using is still registered and not expired.
- Reproduce with curl -i against the same URL to see the full status line and body.
- If the body is a real OAuth error (invalid_grant etc.), address that specific error code rather than retrying blindly.
Example fix
// before — fallback message only says "Failed to start device authorization"
// after — log response.status + raw body excerpt before throwing for easier triage
if (!response.ok) {
const detail = await describeErrorResponse(response, fallback);
console.error(`oauthRequest ${response.url} -> HTTP ${response.status}`);
throw new Error(detail);
} Defensive patterns
Strategy: try-catch
Validate before calling
// Nothing to validate client-side beyond a well-formed URL + client_id;
// surface that the request will go out.
function isValidAuthUrl(u: string): boolean {
try {
const parsed = new URL(u);
return parsed.protocol === "https:" && Boolean(parsed.hostname);
} catch {
return false;
}
}
if (!isValidAuthUrl(baseUrl)) {
throw new Error(`Invalid auth base URL: ${baseUrl}`);
} Type guard
// Detect an HTML (non-OAuth) response body so the caller can tell proxy noise apart.
function looksLikeHtmlExcerpt(msg: string): boolean {
return /\b(?:<html|<!doctype|<body)/i.test(msg);
} Try / catch
try {
await oauthRequest(url, params, fallback);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (looksLikeHtmlExcerpt(msg)) {
throw new Error(`${fallback}: request hit a proxy/gateway HTML page, not the auth server. Check the base URL.`);
}
throw e; // otherwise it's a real OAuth error body — rethrow verbatim
} Prevention
- Verify the auth base URL points at the real auth host, not a gateway that returns HTML errors.
- Confirm client_id is current before initiating the flow; an invalid_client is the most common 4xx here.
- Reproduce failing calls with curl -i to see whether the body is an OAuth error or intermediary noise.
When it happens
Trigger: OAuth device-code/token endpoint returns 4xx with an OAuth error body (invalid_client, invalid_request, invalid_grant); an intermediary (proxy/gateway) returns its own HTML error page; the auth host returns a generic 500/502 JSON; the request reached the wrong virtual host.
Common situations: Wrong/migrated client_id; auth server behind a gateway that returns HTML for errors; base URL override pointing at the wrong service; misconfigured load balancer returning 502 with a non-JSON body; rate-limited by an edge proxy.
Related errors
- Failed to fetch user info
- Could not reach ${url}: ${detail}${code ? ` (${code})` : ""}
- Device token poll failed
- errorBody.error || errorBody.message || res.statusText
- no files
AI-assisted analysis of upstash/context7@ca15df0443 (2026-08-12).
Data as JSON: /api/errors/6dc4d90722ba7951.
Report an issue: GitHub.