upstash/context7 · error · Error
Could not reach ${url}: ${detail}${code ? ` (${code})` : ""}
Error message
Could not reach ${url}: ${detail}${code ? ` (${code})` : ""}\n${hint} What it means
Thrown by postForm() when the underlying fetch() rejects during an OAuth HTTP request. The caught error is passed to describeConnectionError(), which extracts the cause's code/message and maps well-known errno codes (TLS, DNS, connection refused/reset, timeout) to a tailored remediation hint. The result is a multi-line message: 'Could not reach <url>: <detail> (<code>)\n<hint>'.
Source
Thrown at packages/cli/src/utils/auth.ts:214
}
function describeConnectionError(error: unknown, url: string): string {
const { code, message } = getErrorCause(error);
const detail = message || (error instanceof Error ? error.message : String(error));
const hint = (code && CONNECTION_HINTS[code]) || DEFAULT_HINT;
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> {View on GitHub (pinned to ca15df0443)
Solutions
- For TLS errors: export NODE_EXTRA_CA_CERTS=<path-to-org-root-ca.pem> and retry.
- For DNS/connection errors: check VPN status and confirm the host resolves and is reachable (curl -v <url>).
- If behind a proxy, route Node through it via HTTPS_PROXY / global-agent / undici's ProxyAgent, since Node ignores system proxy settings by default.
- For ETIMEDOUT, raise connect timeout or move to a less restrictive network segment.
Example fix
// before — Node ignores system proxy, fetch rejects with ECONNREFUSED
// (no change at call site; fix the environment)
// after — teach Node about the corporate proxy + CA before any fetch
import { setGlobalDispatcher, ProxyAgent } from "undici";
process.env.NODE_EXTRA_CA_CERTS ||= "/etc/ssl/certs/org-root-ca.pem";
setGlobalDispatcher(new ProxyAgent(process.env.HTTPS_PROXY!)); Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-flight: confirm the host resolves and the TLS chain trusts before OAuth.
import { lookup } from "node:dns/promises";
async function canReach(url: string): Promise<boolean> {
try {
const host = new URL(url).hostname;
await lookup(host);
return true;
} catch {
return false;
}
}
if (!(await canReach(authUrl))) {
throw new Error("Auth host unreachable — check VPN/DNS/proxy.");
} Type guard
// Narrow a thrown unknown to a connection-style error with an errno code.
function hasErrnoCode(e: unknown): e is { cause: { code: string; message?: string } } {
return (
typeof e === "object" && e !== null &&
typeof (e as any).cause === "object" &&
typeof (e as any).cause?.code === "string"
);
} Try / catch
try {
await startDeviceAuthorization(baseUrl, clientId);
} catch (e) {
const msg = e instanceof Error ? e.message : String(e);
if (/TLS|certificate/i.test(msg)) {
hintUser("Set NODE_EXTRA_CA_CERTS to your org root CA.");
} else if (/ENOTFOUND|EAI_AGAIN/.test(msg)) {
hintUser("DNS failed — check VPN/network.");
} else if (/ECONNREFUSED|ECONNRESET|EHOSTUNREACH/.test(msg)) {
hintUser("Connection blocked — firewall/proxy may be refusing it.");
} else {
hintUser("If behind a proxy, configure HTTPS_PROXY (Node ignores system proxy).");
}
} Prevention
- On corporate networks, set NODE_EXTRA_CA_CERTS to the org root CA before any auth flow.
- Configure an HTTPS_PROXY dispatcher for Node (undici/global-agent) since the runtime ignores system proxy settings.
- Run a pre-flight DNS/TLS check before kicking off the device flow to fail fast with actionable guidance.
When it happens
Trigger: TLS interception by a corporate proxy (UNABLE_TO_VERIFY_LEAF_SIGNATURE, SELF_SIGNED_CERT_IN_CHAIN, CERT_HAS_EXPIRED); DNS failure for the auth host (ENOTFOUND, EAI_AGAIN); firewall/proxy refusing or resetting the connection (ECONNREFUSED, ECONNRESET, EHOSTUNREACH); connect timeout (UND_ERR_CONNECT_TIMEOUT, ETIMEDOUT).
Common situations: Developer on a corporate network whose TLS-inspecting proxy is not trusted by Node; VPN split-tunnel dropping the auth host; NODE_EXTRA_CA_CERTS not set to the org root CA; HTTPS_PROXY expected but Node does not honor it automatically; auth host moved/decommissioned.
Related errors
- ${fallback} (HTTP ${response.status} from ${response.url}):
- Device token poll failed
- Failed to fetch user info
- no files
AI-assisted analysis of upstash/context7@ca15df0443 (2026-08-12).
Data as JSON: /api/errors/989b1e532ba98e29.
Report an issue: GitHub.