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

  1. For TLS errors: export NODE_EXTRA_CA_CERTS=<path-to-org-root-ca.pem> and retry.
  2. For DNS/connection errors: check VPN status and confirm the host resolves and is reachable (curl -v <url>).
  3. If behind a proxy, route Node through it via HTTPS_PROXY / global-agent / undici's ProxyAgent, since Node ignores system proxy settings by default.
  4. 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

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


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