can1357/oh-my-pi · warning · AbortError
Proxy tunnel aborted
Error message
Proxy tunnel aborted
What it means
connectProxiedSocket tunnels a TLS socket through an HTTP(S) proxy (CONNECT). Before doing any work it checks the caller-supplied AbortSignal and throws AbortError('Proxy tunnel aborted') if the signal is already aborted. This is an intentional cooperative-cancellation guard: the library refuses to start a proxy handshake for an operation that has already been cancelled.
Source
Thrown at packages/ai/src/utils/proxy.ts:286
/** Caller cancellation for the proxy TCP/TLS handshake and CONNECT tunnel. */
signal?: AbortSignal;
/** Maximum wall-clock time to establish the final TLS tunnel. Disabled when absent or non-positive. */
timeoutMs?: number;
/** Target TLS profile. Cursor defaults to HTTP/2 when this is absent. */
tls?: tls.ConnectionOptions;
}
/**
* Tunnel a socket connection through an HTTP CONNECT proxy.
* This is used specifically to wrap Node's `http2.connect(baseUrl, { createConnection })` for Cursor.
*/
export async function connectProxiedSocket(
proxyUrlStr: string,
targetUrlStr: string,
options?: ConnectProxiedSocketOptions,
): Promise<tls.TLSSocket> {
if (options?.signal?.aborted) {
throw new AbortError("Proxy tunnel aborted");
}
const proxyUrl = new URL(proxyUrlStr);
const targetUrl = new URL(targetUrlStr);
const useProxySsl = proxyUrl.protocol === "https:";
const proxyPort = proxyUrl.port ? parseInt(proxyUrl.port, 10) : useProxySsl ? 443 : 80;
const proxyHost = proxyUrl.hostname;
const targetPort = targetUrl.port ? parseInt(targetUrl.port, 10) : 443;
const targetHost = targetUrl.hostname;
const { promise, resolve, reject } = Promise.withResolvers<tls.TLSSocket>();
const readyEvent = useProxySsl ? "secureConnect" : "connect";
let rawSocket: net.Socket | undefined;
let tunnelSocket: tls.TLSSocket | undefined;
let timeout: NodeJS.Timeout | undefined;View on GitHub (pinned to 9690622007)
Solutions
- Check `signal?.aborted` before calling connectProxiedSocket and skip the call if already cancelled
- Create a fresh AbortController per connection attempt instead of reusing an aborted one
- If the abort was unintentional (timeout too aggressive), raise the timeout that triggers controller.abort()
- Handle AbortError distinctly from network failures — do not retry it as a transient error; treat as cancellation
Example fix
// before — reusing a possibly-aborted controller
const socket = await connectProxiedSocket(proxyUrl, targetUrl, { signal: controller.signal });
// after — fresh signal per attempt, bail out early
const controller = new AbortController();
setTimeout(() => controller.abort(), timeoutMs);
if (controller.signal.aborted) return;
const socket = await connectProxiedSocket(proxyUrl, targetUrl, { signal: controller.signal }); Defensive patterns
Strategy: try-catch
Validate before calling
if (options?.signal?.aborted) {
throw new DOMException("Aborted before proxy connect", "AbortError");
} Type guard
function isAbortError(err: unknown): err is Error {
return err instanceof Error && (err.name === "AbortError" || err.message.includes("aborted"));
} Try / catch
try {
const socket = await connectProxiedSocket(proxy, target, { signal });
} catch (err) {
if (isAbortError(err)) return; // cancellation, not a failure — do not retry
throw err;
} Prevention
- Check signal.aborted before initiating each connection attempt
- Use one fresh AbortController per attempt, never recycle aborted signals
- Distinguish AbortError from network errors in your retry policy
- Keep timeout-driven aborts aligned with expected proxy handshake latency
When it happens
Trigger: Calling connectProxiedSocket (directly or via provider fetch/socket setup) with options.signal from an AbortController that was already aborted — e.g. a request timeout fired, the user cancelled, or a race where abort happens between controller creation and the call.
Common situations: Request timeouts that abort the controller before the socket connect begins; retry logic that aborts the previous attempt's signal but reuses it for the new attempt; streaming clients cancelled by the consumer while the connection was still being established; global shutdown/dispose aborting all in-flight signals.
Related errors
- Internal TLS bridge did not bind to a TCP address
- ${errorMessage(first.error)}${outputSuffix()}
- Proxy configuration uses a scheme Bun's fetch cannot use${de
- Mojeek search timed out.
- timed out: {command}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/e81432d7f4e90f61.
Report an issue: GitHub.