can1357/oh-my-pi · error · AnthropicConnectionError
AnthropicConnectionError
Error message
AnthropicConnectionError
What it means
AnthropicClient.#send retries fetch-level failures (network errors) up to maxRetries with backoff. If the final attempt still throws a low-level network error (and it is not already a connection-timeout error), it is wrapped in AnthropicConnectionError. This means the client could not establish or complete the HTTP connection to the Anthropic API at all — DNS failure, connection refused/reset, TLS error, or socket hang-up.
Source
Thrown at packages/ai/src/providers/anthropic-client.ts:245
const maxRetryDelayMs = options?.maxRetryDelayMs ?? opts.maxRetryDelayMs ?? 60_000;
const url = `${opts.baseURL ?? "https://api.anthropic.com"}${path}`;
const headers = this.#buildHeaders(options?.headers);
const body = JSON.stringify(params);
for (let attempt = 0; ; attempt++) {
if (callerSignal?.aborted) throw createAbortError();
let response: Response;
try {
response = await this.#fetchOnce(fetchFn, url, headers, body, timeoutMs, callerSignal);
} catch (error) {
if (callerSignal?.aborted) throw createAbortError();
if (attempt < maxRetries) {
await this.#backoff(attempt, undefined, callerSignal);
continue;
}
if (error instanceof AIError.AnthropicConnectionTimeoutError) throw error;
throw new AIError.AnthropicConnectionError(error);
}
if (response.ok) return response;
if (attempt < maxRetries && shouldRetryResponse(response)) {
// Bound the server-directed wait: an over-cap `retry-after` declines
// the retry and surfaces the original error (status/body/headers
// intact) so higher-level recovery can run. A non-positive cap disables enforcement.
// Checked before draining the body so `fromResponse` can still read it.
const headerDelayMs = retryDelayFromHeaders(response.headers);
if (headerDelayMs !== undefined && maxRetryDelayMs > 0 && headerDelayMs > maxRetryDelayMs) {
throw await AIError.AnthropicApiError.fromResponse(response, callerSignal);
}
await response.body?.cancel().catch(() => {});
await this.#backoff(attempt, response.headers, callerSignal);
continue;
}
View on GitHub (pinned to 9690622007)
Solutions
- Check basic connectivity to the API endpoint (curl -v https://api.anthropic.com) and fix network/VPN/proxy issues
- Verify ANTHROPIC_BASE_URL (or configured baseURL) — wrong host, port, or scheme produces exactly this wrapped failure
- Inspect the wrapped `cause` of AnthropicConnectionError for the underlying errno (ENOTFOUND, ECONNREFUSED, etc.) to target the fix
- Increase maxRetries if failures are transient (flaky networks), and add application-level backoff for long outages
- If behind a corporate proxy, configure HTTPS_PROXY and the agent options the client accepts
Example fix
// before: no diagnostics, fails in prod VPC
const client = new AnthropicClient(apiKey);
// after: explicit endpoint + cause logging
try {
await client.request(...);
} catch (e) {
if (e instanceof AIError.AnthropicConnectionError) {
logger.error("anthropic unreachable", { cause: e.cause?.message, baseURL });
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// pre-flight endpoint sanity check
const url = new URL(baseURL ?? "https://api.anthropic.com");
if (url.protocol !== "https:" && process.env.NODE_ENV === "production") {
throw new Error(`Anthropic baseURL must be https in production: ${url}`);
} Type guard
import { AIError } from "@oh-my-pi/pi-ai";
function isAnthropicConnectionError(e: unknown): e is AIError.AnthropicConnectionError {
return e instanceof AIError.AnthropicConnectionError;
} Try / catch
try {
return await client.request(req);
} catch (e) {
if (isAnthropicConnectionError(e)) {
// network-level failure after retries; log cause (ENOTFOUND/ECONNREFUSED/TLS) and back off
logger.error("anthropic unreachable", { cause: (e.cause as Error)?.message });
await Bun.sleep(retryDelay);
return client.request(req); // or surface a user-facing outage error
}
throw e;
} Prevention
- Verify base URL, DNS, and proxy/VPN reachability in CI health checks before deploys
- Log the wrapped cause errno to distinguish DNS vs refused vs TLS failures
- Keep client maxRetries modest and add circuit breaking for sustained outages
- Configure HTTPS_PROXY/agent settings explicitly in corporate networks
When it happens
Trigger: fetch() throwing on any attempt of a request() call and retries exhausted: DNS resolution failure, ECONNREFUSED/ECONNRESET, TLS handshake failure, proxy misconfiguration, or the machine being offline.
Common situations: Corporate proxies/firewalls blocking api.anthropic.com; ANTHROPIC_BASE_URL pointing at a wrong port or a down local gateway; VPN required but not connected; IPv6/DNS issues in containers; transient network blips exceeding the retry budget.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- AnthropicConnectionTimeoutError
- stream ended before message_stop
- xAI device-code request failed: ${error instanceof Error ? e
- Failed to fetch Umans models info
- Gemini Files API upload initialization request failed
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/b62ba705c723c90d.
Report an issue: GitHub.