musistudio/claude-code-router · error · Error

Failed to start MITM server for ${hostname}

Error message

Failed to start MITM server for ${hostname}

What it means

The proxy service failed to bind a local MITM listener for a CONNECTed hostname. After calling listen(server, 0, "127.0.0.1"), server.address() returned null or a string (pipe name), which should not happen for a TCP listener, so the half-started server is closed and this error thrown.

Source

Thrown at packages/core/src/proxy/service.ts:690

    const authority = this.authority ?? readProxyCertificateAuthority();
    const certificate = createCertificateForHost(hostname, authority);
    const server = https.createServer(
      {
        ALPNProtocols: ["http/1.1"],
        cert: certificate.cert,
        key: certificate.key
      },
      (request, response) => {
        void this.handleProxyRequest(request, response, "https:").catch((error) => {
          sendProxyError(response, 502, formatError(error));
        });
      }
    );
    await listen(server, 0, "127.0.0.1");
    const address = server.address();
    if (!address || typeof address === "string") {
      await closeServer(server);
      throw new Error(`Failed to start MITM server for ${hostname}`);
    }
    return {
      host: hostname,
      port: address.port,
      server
    };
  }

  private async handleProxyRequest(request: IncomingMessage, response: ServerResponse, defaultProtocol: "http:" | "https:"): Promise<void> {
    if (!this.config) {
      sendProxyError(response, 503, "Proxy service is not configured.");
      return;
    }

    const requestId = randomUUID();
    const targetUrl = resolveRequestUrl(request, defaultProtocol);
    const pluginRoute = pluginService.resolveProxyRoute(targetUrl);
    if (!pluginRoute && isCursorAgentProxyRequest(targetUrl)) {

View on GitHub (pinned to 99f24806c6)

Solutions

  1. Retry the CONNECT request (transient bind failure) after a short delay
  2. Raise fd/ephemeral port limits (ulimit -n, net.ipv4.ip_local_port_range) if many tunnels are open
  3. Reduce concurrent MITM connections or reuse the existing MITM server for that hostname
  4. Inspect system-level socket exhaustion (ss -s, lsof) if it persists

Example fix

// before
const mitm = await proxy.getMitmServer(hostname); // throws

// after
import { retry } from "./retry";
const mitm = await retry(() => proxy.getMitmServer(hostname), { attempts: 3, backoffMs: 200 });
Defensive patterns

Strategy: retry

Try / catch

try { return await withMitm(hostname); } catch (e) { if (e.message.includes("Failed to start MITM server")) return await delayThenRetry(200, () => withMitm(hostname)); throw e; }

Prevention

When it happens

Trigger: CONNECT tunneling to a hostname when the ephemeral 127.0.0.1 listener fails to yield an inet address: address exhaustion (no free ports), file descriptor limits, or an unexpected server state where address() is null right after listen.

Common situations: Heavy parallel CONNECT tunnels exhausting ephemeral ports or fd ulimit; embedded environment with restricted networking; races where the server closes immediately after listen.

Related errors


AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27). Data as JSON: /api/errors/c92c866db9e63a6b. Report an issue: GitHub.