Skip to content

[Bug]: JS SDK: one HTTP/2 GOAWAY (ENHANCE_YOUR_CALM) from the sandbox.e2b.app edge permanently breaks files.write process-wide; undici 8.8.0 never recovers the session #1641

Description

@nischayv

Sandbox ID or Build ID

ilsr5jnqvfbe9ez17h0b8 (one of many affected)

Environment

e2b (JS SDK) 2.38.0, Node 22.23.2 on Linux (Fly.io) and Node 23.6.0 on macOS 14. loadUndici selects the undici8 optional dependency, which resolves to undici 8.8.0.

Timestamp of the issue

First seen 2026-08-04 00:42 UTC; cause chains captured 2026-08-04 14:29 UTC.

Frequency

Happens every time

Expected behavior

When the server ends an HTTP/2 session (GOAWAY), the cost should be at most the in-flight requests. The SDK (or undici underneath it) should open a fresh connection for subsequent requests, and ideally retry streams the server refused, per RFC 9113 §8.7.

Actual behavior

Once one files.write fails with:

TypeError: fetch failed
  cause: Error: Stream closed with error code NGHTTP2_ENHANCE_YOUR_CALM (ERR_HTTP2_STREAM_ERROR)

every subsequent files.write in the process fails with NGHTTP2_INTERNAL_ERROR, including immediate retries, across all sandboxes, until the process restarts. Filesystem calls that go through the connect-RPC transport (files.makeDir) keep working on the same sandbox at the same moment, because that transport uses a separate dispatcher.

This took our chat product down: since 2.25.0 all sandboxes' envd traffic shares the single origin sandbox.e2b.app, and undici multiplexes up to 100 streams per H2 session, so a long-lived server effectively rides one session. One GOAWAY on it breaks file writes process-wide.

Issue reproduction

Hard to trigger from a fresh script (a new process has a fresh session with no accumulated history). Reliable in a long-lived Node server that:

  1. Creates a pool of sandboxes and uploads a few MB to each with files.write
  2. Lets them idle 1-3 minutes
  3. On acquire, bursts ~15 parallel small files.write calls

After some process uptime, the edge in front of sandbox.e2b.app sends ENHANCE_YOUR_CALM (its rapid-reset / stream-abuse protection) and the failure mode above begins.

Additional context

Root cause is a combination of a server behavior and a client bug:

Workaround we verified A/B: patching buildDispatchedFetch to allowH2: false (HTTP/1.1, the pre-2.19.5 transport) fully resolves it under identical load. There is currently no supported way to do this: no env var, no ConnectionConfig option, and no custom fetch injection, so we're shipping a pnpm patch.

Suggested fixes, any of which would let us drop the patch:

  1. Bump the undici8 dependency to >= 8.10.0
  2. Ship the in-house retry for H2 stream resets promised in fix(sdks): robust http2 transport reset retries #1495
  3. Expose an opt-out (env var or ConnectionConfig option) for HTTP/2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions