decolua/9router · error

Passthrough error: ${e.message}

Error message

Passthrough error: ${e.message}

What it means

In passthroughHttps, the http.request forwarded to the real upstream emits an 'error' on the request object. The handler logs 'Passthrough error: <message>', writes it to the dump, replies 502 Bad Gateway ('Bad Gateway' body) if headers were not sent.

Source

Thrown at src/mitm/server.js:283

      forwardRes.pipe(res);
      return;
    }

    const chunks = [];
    forwardRes.on("data", chunk => {
      if (dumper) dumper.writeChunk(chunk);
      if (onResponse) chunks.push(chunk);
      res.write(chunk);
    });
    forwardRes.on("end", () => {
      if (dumper) dumper.end();
      res.end();
      if (onResponse) try { onResponse(Buffer.concat(chunks), forwardRes.headers); } catch { /* ignore */ }
    });
  });

  forwardReq.on("error", (e) => {
    err(`Passthrough error: ${e.message}`);
    if (dumper) { dumper.writeChunk(`\n[ERROR] ${e.message}\n`); dumper.end(); }
    if (!res.headersSent) res.writeHead(502);
    res.end("Bad Gateway");
  });

  if (bodyBuffer.length > 0) forwardReq.write(bodyBuffer);
  forwardReq.end();
}

// ── Request handler ───────────────────────────────────────────

const server = https.createServer(sslOptions, async (req, res) => {
  try {
    if (req.url === "/_mitm_health") {
      res.writeHead(200, { "Content-Type": "application/json" });
      res.end(JSON.stringify({ ok: true, pid: process.pid }));
      return;
    }

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Check the underlying code (ENOTFOUND/ECONNREFUSED/ETIMEDOUT) to distinguish DNS vs connectivity vs timeout.
  2. Fix DNS/hosts entries if the domain resolves to a stale MITM IP.
  3. Verify outbound internet/VPN connectivity with curl to the target domain.
  4. Retry on timeout — transient upstream outages surface here.

Example fix

// before
getaddrinfo ENOTFOUND api.example.com → 502 Bad Gateway
// after
# fix hosts/DNS, then verify
nslookup api.example.com && curl -I https://api.example.com
Defensive patterns

Strategy: retry

Validate before calling

try {
  const addr = await dns.promises.lookup(targetHost);
  console.log(`[mitm] ${targetHost} -> ${addr.address}`);
} catch (e) {
  return respond502(`DNS failure: ${e.code}`); // ENOTFOUND caught before forwarding
}

Type guard

function isDnsError(e) { return e && (e.code === 'ENOTFOUND' || e.code === 'EAI_AGAIN'); }
function isConnRefused(e) { return e && e.code === 'ECONNREFUSED'; }

Try / catch

forwardReq.on('error', (e) => {
  err(`Passthrough error: ${e.message}`);
  if (isDnsError(e) || isConnRefused(e)) {
    if (!res.headersSent) res.writeHead(502, { 'Content-Type': 'application/json' });
    return res.end(JSON.stringify({ error: { message: e.message, hint: 'check DNS/upstream' } }));
  }
  if (!res.headersSent) res.writeHead(502);
  res.end('Bad Gateway');
});

Prevention

When it happens

Trigger: The HTTPS forwarding request fails before a response — DNS ENOTFOUND on the target host, ECONNREFUSED/ETIMEDOUT connecting to port 443, TLS handshake failure, or socket destroyed early.

Common situations: Hosts-file/DNS override pointing the domain at a dead IP; no network/VPN; upstream provider outage; SNI/TLS interception interference from corporate proxies.

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


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/b37d019c84c0fb01. Report an issue: GitHub.