Skip to content

Root-cause forwarded-port truncation in Dev Containers (investigation only, no repo changes) - #11942

Draft
Alex Ross (alexr00) with Copilot wants to merge 1 commit into
mainfrom
copilot/fix-content-length-mismatch
Draft

Alex Ross (alexr00) with Copilot wants to merge 1 commit into
mainfrom
copilot/fix-content-length-mismatch

Conversation

Copilot AI commented Nov 5, 2026 •

Copy link
Copy Markdown

Responses sent through a Dev Containers forwarded port are cut short under load. Browsers report ERR_CONTENT_LENGTH_MISMATCH and curl exits with code 18. The bug still reproduces on VS Code 1.145, which already includes microsoft/vscode#338875.

This PR has no file changes. This repo has no port-forwarding code; the fix belongs in the closed-source Dev Containers extension.

Root cause

  • For each forwarded connection, the extension runs docker exec -i <container> node -e <relay> (relay script quoted in DevContainer Port Forwarding terminates prematurely #11707).
  • When the app's socket closes, the relay calls process.exit() immediately. Any response bytes still queued on process.stdout are lost. Under docker exec -i, stdout is a pipe (FIFO), and Node writes to pipes asynchronously on POSIX.
  • This explains why it only affects Dev Containers (WSL uses a different transport), why it depends on load, and why #338875 didn't help (that change was to VS Code's side of the forwarding).
  • DevContainer Port Forwarding terminates prematurely #11707 reached the same diagnosis and includes a patch its reporter tested.

Local reproduction using the extension's per-connection docker exec approach and the exact relay from #11707. Load was 1 MB responses, 40 parallel requests × 3 runs × 4 rounds (480 requests):

Relay Complete Truncated
Current (process.exit on close) 442 38
Waits for stdout to drain before exiting 480 0

Proposed fix (Dev Containers extension)

client.on('close', hadError => {
  const code = hadError ? 1 : 0;
  // client.pipe(process.stdout) never ends stdout, so end it explicitly or 'finish' never fires
  if (!process.stdout.writableEnded && !process.stdout.destroyed) process.stdout.end();
  if (process.stdout.writableFinished) process.exit(code);
  process.stdout.once('finish', () => process.exit(code));
  process.stdout.once('error', () => process.exit(1));
});

This is a condensed form of the #11707 patch; that original form is the one that produced the 480/480 result above.

Secondary findings

  • Exit on stdin close: if the client closes its sending side after the request, the relay exits and returns 0 bytes, even with the fix above. It should call client.end() instead. This change is untested, and browsers and curl don't close their sending side this way, so it isn't behind this issue.
  • Slow-reader cutoff (~12 s, reported on VS Code 1.122, before #338875): a forwarder that ignores backpressure and calls destroy() on close produces the same symptom. That matches what _mirrorGenericSocket in VS Code did before #338875. The cutoff is a fixed amount of data (~2.7 MB at both 300 KB/s and 150 KB/s), not a timer. #338875 likely fixed this, but I haven't confirmed that Dev Containers goes through that code path.

Open questions

Copilot AI changed the title [WIP] Fix net::ERR_CONTENT_LENGTH_MISMATCH on port-forwarding Root-cause forwarded-port truncation in Dev Containers (investigation only, no repo changes) Nov 5, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

net::ERR_CONTENT_LENGTH_MISMATCH returning large content when port-forwarding from devcontainer

2 participants