Skip to content

fix(api): remove ReadTimeout to prevent premature body-read failures under high concurrency - #3416

Open
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:fix/api-remove-read-timeout
Open

fix(api): remove ReadTimeout to prevent premature body-read failures under high concurrency#3416
AdaAibaby wants to merge 1 commit into
e2b-dev:mainfrom
AdaAibaby:fix/api-remove-read-timeout

Conversation

@AdaAibaby

@AdaAibaby AdaAibaby commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Closes #3415

Summary

  • Remove ReadTimeout: maxReadTimeout (10s) from http.Server in packages/api/main.go
  • Remove the now-unused maxReadTimeout constant
  • ReadHeaderTimeout: 5s is retained for slowloris protection

Why

ReadTimeout starts from TCP accept, including scheduler queue time. Under high concurrency goroutines queue for >10s before being scheduled, so the deadline fires before io.ReadAll ever executes — producing i/o timeout errors that look like client disconnects or auth failures. The intended per-request ceiling is requestTimeout: 70s (middleware context deadline), which is never reached in practice because ReadTimeout fires first.

Request bodies on this API are small JSON payloads sent in a single TCP segment. Once headers arrive (guarded by ReadHeaderTimeout), there is no meaningful slow-body attack surface to protect against.

Test plan

  • Build passes: go build ./packages/api/...
  • Deploy to staging, replay high-concurrency load (≥ 100 simultaneous sandbox creates); confirm i/o timeout body-read errors disappear from logs
  • Confirm /health still responds correctly under load
  • Confirm slowloris protection still active: a client that opens a TCP connection but never sends headers is rejected within 5s (ReadHeaderTimeout)
    /cc @jakubno @dobrac @ValentaTomas @arkamar @tvi Looking forward to your code review.

…under load

ReadTimeout: 10s starts counting from TCP connection acceptance, including
time the goroutine spends queued in the scheduler. Under high concurrency
(hundreds of simultaneous requests) goroutines can wait >10s before being
scheduled to read the body, causing the connection to be killed mid-read
with an i/o timeout error.

This conflicts with requestTimeout: 70s, the intended per-request deadline.
ReadTimeout is meant to bound the entire read phase but it becomes the
binding constraint under load — not because clients are slow, but because
the server scheduler cannot drain the goroutine queue fast enough.

ReadHeaderTimeout: 5s is kept to guard against slowloris header attacks.
Request bodies on this API are small JSON payloads sent in a single TCP
segment, so there is no meaningful slow-body attack surface once headers
are received. The requestTimeout middleware context (70s) provides the
real per-request ceiling for handler execution.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

api: ReadTimeout: 10s kills body reads under high concurrency, conflicting with requestTimeout: 70s

2 participants