Skip to content

fix(eve): forward each dev request on a fresh worker connection - #5004

Open
roboeve[bot] wants to merge 2 commits into
triage/5001-reprofrom
triage/5001-fix
Open

roboeve[bot] wants to merge 2 commits into
triage/5001-reprofrom
triage/5001-fix

Conversation

@roboeve

@roboeve roboeve Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #5001

Stacked on the repro in #5003. eve dev now forwards each request to the dev worker on its own connection, so a busy parent can no longer send one on a pooled socket the worker already closed.

Why

env-runner's BaseEnvRunner.fetch calls httpxy's proxyFetch without proxy options, so every forward goes through httpxy's shared keep-alive http.Agent, which has no idle timeout. The worker's HTTP server closes idle sockets after its keep-alive timeout, and the parent only notices when its event loop reads the FIN. Under CPU load the parent can dispatch a forward before that, the forward throws, and the dev server answers 503 (socket hang up / read ECONNRESET). The request never reaches the agent.

Approach

The vendor step now patches that one call to pass { agent: false }, the same way it already patches env-runner's worker shutdown. Each forward then opens a fresh loopback connection and closes it after the response, so there is no pool to go stale. The plugin throws if env-runner's source changes, so an upgrade cannot silently drop the patch. The extra loopback handshake per request is negligible in dev, and eve start has no forwarding hop, so it is unaffected.

Also considered:

  • Sending connection: close on each forward (the first push here): the worker's response can override it. The MCP SDK's SSE responses set connection: keep-alive, so Node's client returned the socket to the pool while the worker's parser rejected the next request with an empty 400. The mcp-agent-channel scenario caught this.
  • Retrying on a reused-socket reset: the request body is streamed, so a retry would need buffering.
  • Raising the worker's keep-alive timeout: narrows the window but keeps the race.

Validation

  • Repro head (it.fails removed): forwards a request after the parent stalls past the worker keep-alive timeout gets 503 {"error":"socket hang up"}.
  • This head, after pnpm --filter eve build: drained-nitro-dev-server.scenario.test.ts and mcp-agent-channel.scenario.test.ts → 17 passed.
  • Full scenario suite in a local sandbox without Docker: 498 passed, 9 failed. All 9 fail inside eve build or packed-package loading (production-build-isolation, app-runtime-dependencies, package-consumption, react-server-module-map, ai/package), and all 9 passed in CI on the previous push.
  • pnpm run typecheck, oxlint, and oxfmt --check pass.
  • Isolated check against a live dev worker: 4 sequential MCP POSTs through proxyFetch with connection: close → 200 400 200 400; with { agent: false } → 200 200 200 200, each on a new connection.

Fixes #5001

Co-authored-by: ruiconti <1834568+ruiconti@users.noreply.github.com>
@vercel

vercel Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
eve-docs Ready Ready Preview, v0 Oct 17, 2026 11:39pm UTC
eve-pkg Ready Ready Preview, v0 Oct 17, 2026 11:39pm UTC

@github-actions

github-actions Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Bundle + Package Summary: apps/fixtures/weather-agent

Key takeaways

  • No notable deltas vs triage/5001-repro (ab8cb30).

Delta vs triage/5001-repro (ab8cb30)

Area Metric Baseline Current Delta
Package Packed tarball 7.66 MB 7.66 MB -174 B ✅
Package Unpacked publish size 26.97 MB 26.98 MB +11 B ⚠️
Package Installed footprint 75.11 MB 75.11 MB +11 B ⚠️
Package Published files 4171 4171 0
Package Installed files 8182 8182 0
Package Installed package instances 34 34 0
Package Distinct installed package names 32 32 0
Package Installed dependency edges 51 51 0
Package Installed optional peer edges 9 9 0
Runtime Unique function payloads 2 2 0
Runtime Total function bytes 20.77 MB 20.77 MB -120 B ✅
Runtime Public routes 18 18 0
Changed function payloads vs triage/5001-repro (ab8cb30) (2)
Function Status Baseline Current Delta Route changes
functions/__server.func changed 10.38 MB 10.38 MB -60 B ✅ none
functions/.well-known/workflow/v1/flow.func changed 10.38 MB 10.38 MB -60 B ✅ none

eve init install

Metric Baseline Current Delta
Installed footprint 113.50 MB 113.50 MB +11 B ⚠️
Installed packages 97 97 0
dependencies 4 4 0
devDependencies 2 2 0
Dependency package bytes 45.25 MB 45.25 MB +11 B ⚠️
devDependency package bytes 5.11 MB 5.11 MB 0 B ➖
Build Metadata
  • Preset: vercel
  • Nitro: nitro@3.0.260903-beta
  • Output directory: apps/fixtures/weather-agent/.vercel/output
  • Build metadata timestamp: 2026-10-17T23:39:19.801Z
  • Route aliases: 18 public, 1 internal (19 total aliases)
  • Vercel routes in config: 21
  • Severity legend: 🔴 dominant/large, 🟠 notable, 🟡 watch, ⚪ small
Package Drill-Down

Package Details

  • Package: eve@0.80.1
  • Package directory: packages/eve
  • Tarball: 7.66 MB (eve-0.80.1.tgz)
  • Unpacked payload: 26.98 MB across 4171 published files
  • Installed footprint: 75.11 MB across 8182 installed files
  • Installed root package: 26.97 MB
  • Installed dependencies: 48.14 MB
  • Installed package instances: 34
  • Distinct installed package names: 32
  • Installed dependency edges: 51
  • Installed optional peer edges: 9
  • Runtime dependencies: 2
  • Peer dependencies: 7 (6 optional)

Installed footprint is measured from an isolated temporary npm install of the packed tarball.
Graph metrics read only package.json files in package directories directly beneath a node_modules boundary, including nested boundaries. Each directory is one package instance; distinct names come from those manifests. Dependency edges count each unique name in dependencies or optionalDependencies per instance; optional peer edges count peerDependencies marked optional.

Heavy installed dependencies

  • eve: 26.97 MB (35.9%)
  • @rolldown/binding-linux-x64-gnu: 19.81 MB (26.4%)
  • ai: 8.24 MB (11.0%)
  • zod: 6.15 MB (8.2%)
  • undici: 3.58 MB (4.8%)
Publish payload breakdown
Published file size
🟠 dist/src/compiled/shadcn-registry/index.js       [#####...................] 3.85 MB 14.3%
🟠 dist/src/compiled/@photon-ai/chat-adapter-ime... [###.....................] 2.29 MB 8.5%
🟠 dist/src/compiled/@ai-sdk/code-mode/index.js     [#.......................] 1.03 MB 3.8%
🟡 dist/src/compiled/@vercel/blob/index.js          [#.......................] 604.9 kB 2.2%
🟡 dist/src/compiled/_chunks/workflow/undici-D-I... [#.......................] 521.9 kB 1.9%
🔴 Other published files                            [########################] 18.68 MB 69.3%
Installed footprint breakdown
Installed package size
🔴 eve                             [########################] 26.97 MB 35.9%
🔴 @rolldown/binding-linux-x64-gnu [##################......] 19.81 MB 26.4%
🔴 ai                              [#######.................] 8.24 MB 11.0%
🔴 zod                             [#####...................] 6.15 MB 8.2%
🟠 undici                          [###.....................] 3.58 MB 4.8%
🟠 nitro                           [##......................] 1.89 MB 2.5%
🔴 Other installed packages        [########................] 8.46 MB 11.3%
Runtime dependencies (2)
Package Range Notes
nitro 3.0.260903-beta
undici 8.10.2
Peer dependencies (7)
Package Range Notes
@opentelemetry/api ^1.0.0 optional peer
ai catalog:
braintrust ^3.0.0 optional peer
chat ^4.42.0 optional peer
dd-trace ^6.13.0 optional peer
just-bash ^3.1.0 optional peer
microsandbox ^0.5.0 optional peer
eve init install drill-down

eve init install details

  • Command: eve init my-agent
  • Package manager: npm
  • Installed footprint: 113.50 MB across 10099 installed files
  • Installed packages: 97 total (91 transitive-only)
  • dependencies: 4 direct packages totaling 45.25 MB
  • devDependencies: 2 direct packages totaling 5.11 MB
  • Other transitive package files: 63.14 MB

Installed footprint is measured from an isolated temporary eve init my-agent using the current packed eve tarball.

Heavy installed dependencies

  • @typescript/typescript-linux-x64: 27.95 MB (24.6%)
  • eve: 26.97 MB (23.8%)
  • @rolldown/binding-linux-x64-gnu: 19.81 MB (17.5%)
  • zod: 9.76 MB (8.6%)
  • ai: 8.24 MB (7.3%)
Installed footprint breakdown
Installed package size
🔴 @typescript/typescript-linux-x64 [########################] 27.95 MB 24.6%
🔴 eve                              [#######################.] 26.97 MB 23.8%
🔴 @rolldown/binding-linux-x64-gnu  [#################.......] 19.81 MB 17.5%
🔴 zod                              [########................] 9.76 MB 8.6%
🔴 ai                               [#######.................] 8.24 MB 7.3%
🟠 undici                           [###.....................] 3.58 MB 3.1%
🔴 Other installed packages         [###############.........] 17.19 MB 15.1%
dependencies (4)
Package Range Installed size Share
@vercel/connect 2.5.2 276.3 kB 0.2%
ai ^7.0.137 8.24 MB 7.3%
eve file:eve-0.80.1.tgz 26.97 MB 23.8%
zod 4.5.4 9.76 MB 8.6%
devDependencies (2)
Package Range Installed size Share
@types/node 24.x 2.61 MB 2.3%
typescript 7.0.2 2.50 MB 2.2%
Function Drill-Down

Payload Size Graph

Unique function payload size and share of total
🔴 functions/.well-known/workflow/v1/flow.func     [########################] 10.38 MB 50.0%
🔴 functions/__server.func                         [########################] 10.38 MB 50.0%

Top Function Payloads

🟠 functions/.well-known/workflow/v1/flow.func • 1 public route • 10.38 MB
Metric Value
Public routes /.well-known/workflow/v1/flow
Runtime nodejs24.x
Handler index.mjs
Payload 10.38 MB
Function files 10.38 MB across 122 files
Traced dependencies 0 B
Signal 🟠 Bundled file _chunks/vercel.web.mjs is 2.38 MB (22.9%)

🟠 🔎 Dependency Analysis

📦 Bundled files:

Bundled file size
🟠 _chunks/vercel.web.mjs                         [############............] 2.38 MB 22.9%
🟠 _libs/undici.mjs                               [#####...................] 1.01 MB 9.7%
🟡 _chunks/sandbox3.mjs                           [####....................] 815.4 kB 7.9%
🟡 _chunks/compiled-artifacts-instrumentation.mjs [####....................] 734.8 kB 7.1%
🟡 _chunks/token-util-Bla5Z0G9.mjs                [####....................] 704.7 kB 6.8%
🔴 Other bundled files                            [########################] 4.74 MB 45.7%

🧾 Vercel Config

{
  "handler": "index.mjs",
  "launcherType": "Nodejs",
  "shouldAddHelpers": false,
  "supportsResponseStreaming": true,
  "runtime": "nodejs24.x",
  "maxDuration": "max",
  "experimentalTriggers": [
    {
      "type": "queue/v2beta",
      "topic": "__eve776561746865722d6167656e74_wkf_workflow_*",
      "consumer": "default",
      "retryAfterSeconds": 5,
      "initialDelaySeconds": 0
    }
  ],
  "environment": {
    "WORKFLOW_PRECONDITION_GUARD": "1"
  }
}

🟠 functions/__server.func • 17 public routes, 1 internal alias • 10.38 MB
Metric Value
Public routes /
/.well-known/workflow/v1/webhook/[token]
/eve/v1/callback/[token]
/eve/v1/connections/[name]/callback/[attemptId]/[token]
/eve/v1/connections/[name]/callback/[token]
/eve/v1/health
/eve/v1/info
/eve/v1/session
/eve/v1/session/[parentSessionId]/subagents/[callId]/[childSessionId]/stream
/eve/v1/session/[sessionId]
/eve/v1/session/[sessionId]/cancel
/eve/v1/session/[sessionId]/clear
/eve/v1/session/[sessionId]/compact
/eve/v1/session/[sessionId]/reset
/eve/v1/session/[sessionId]/stream
/eve/v1/session/[sessionId]/stubs
/eve/v1/task-input/[token]
Internal aliases /__server
Runtime nodejs24.x
Handler index.mjs
Payload 10.38 MB
Function files 10.38 MB across 122 files
Traced dependencies 0 B
Signal 🟠 Bundled file _chunks/vercel.web.mjs is 2.38 MB (22.9%)

🟠 🔎 Dependency Analysis

📦 Bundled files:

Bundled file size
🟠 _chunks/vercel.web.mjs                         [############............] 2.38 MB 22.9%
🟠 _libs/undici.mjs                               [#####...................] 1.01 MB 9.7%
🟡 _chunks/sandbox3.mjs                           [####....................] 815.4 kB 7.9%
🟡 _chunks/compiled-artifacts-instrumentation.mjs [####....................] 734.8 kB 7.1%
🟡 _chunks/token-util-Bla5Z0G9.mjs                [####....................] 704.7 kB 6.8%
🔴 Other bundled files                            [########################] 4.74 MB 45.7%

🧾 Vercel Config

{
  "handler": "index.mjs",
  "launcherType": "Nodejs",
  "shouldAddHelpers": false,
  "supportsResponseStreaming": true,
  "runtime": "nodejs24.x"
}

Build Timing: e2e/fixtures/agent-tools-sandbox

This is an informational timing measurement inside eve build, from preflight through publication. Output-size measurement and profile writing are excluded.

Build mode: deployable Vercel build with sandbox template prewarm included.

  • Build pipeline: 3.76 s -> 3.63 s (-130.1 ms) vs triage/5001-repro (ab8cb30).
  • Timing is informational: shared GitHub runners are too variable for a hard timing budget.
Detailed phase timings vs `triage/5001-repro (ab8cb30)`
Phase Baseline Current Delta
extension.check 18.0 ms 17.8 ms -0.2 ms
project.resolve 7.0 ms 0.4 ms -6.6 ms
workspace.create 1.0 ms 0.6 ms -0.4 ms
host.prepare 749.2 ms 716.4 ms -32.8 ms
vercel.service-prefix.resolve 1.9 ms 1.6 ms -0.3 ms
nitro.create 691.2 ms 682.5 ms -8.7 ms
sandbox.prewarm 306.4 ms 248.2 ms -58.2 ms
nitro.cache.prepare 0.3 ms 0.3 ms 0.0 ms
nitro.prepare 0.7 ms 0.7 ms 0.0 ms
nitro.public-assets 0.8 ms 0.8 ms 0.0 ms
nitro.prerender 0.6 ms 0.6 ms 0.0 ms
nitro.bundle 1.84 s 1.82 s -17.4 ms
nitro.cache.write 0.4 ms 0.4 ms 0.0 ms
vercel.workflow-function.materialize 59.3 ms 56.4 ms -2.9 ms
agent-summary.emit 0.6 ms 0.7 ms +0.1 ms
connect-manifest.emit 0.3 ms 0.3 ms 0.0 ms
nitro.close 0.1 ms 0.1 ms 0.0 ms
output.publish 3.6 ms 3.6 ms 0.0 ms
workspace.remove 2.9 ms 2.9 ms 0.0 ms

@roboeve

roboeve Bot commented Oct 17, 2026

Copy link
Copy Markdown
Contributor Author

CI's test-scenario failure is a real regression from this PR, not a flake. mcp-agent-channel.scenario.test.ts fails here and passes on the repro base (#5003). I reproduced both locally on 55b902d.

What breaks: the legacy MCP agent_start call gets HTTP 400 with an empty body. A clientError hook in the worker shows Node rejecting the forwarded request with HPE_CLOSED_CONNECTION: Data after Connection: close at bytesParsed: 1. The parent sent it on a socket where the previous request already had connection: close.

Why: the legacy initialize reply is SSE, and the MCP SDK sets an explicit Connection: keep-alive response header. Node's client decides reuse from the response, so httpxy's keep-alive agent pools the socket. Node's server decides from the request and closes after responding, then rejects the next request on that socket. So connection: close on the request does not reliably keep the pool empty. Any worker response that sets its own Connection header defeats it.

Options:

  • Forward with agent: false or a short idle timeout. env-runner's BaseEnvRunner.fetch calls httpxy proxyFetch(address, input, init) with no proxy options, so this needs an upstream env-runner option or our own forward through private _address.
  • Strip hop-by-hop Connection from worker responses. That would have to live in the Nitro dev entry and only patches this symptom.

I haven't pushed anything since this changes the approach. Leaving it as a draft. The E2E workflow-retention rerun I triggered is unrelated to this.

Sending connection: close broke MCP SSE: the worker answers with connection: keep-alive, so the socket went back to the pool and the next request got an empty 400. Patch env-runner's proxyFetch call to use agent: false instead, so each forward opens its own loopback connection.

Refs #5001

Co-authored-by: ruiconti <1834568+ruiconti@users.noreply.github.com>

This branch was successfully deployed

2 active deployments
Preview – eve-docs — f291ee81 Deployed Oct 17, 2026 by vercel[bot]
Preview – eve-pkg — f291ee81 Deployed Oct 17, 2026 by vercel[bot]
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.

eve dev intermittently answers 503 {"error":"read ECONNRESET"} to channel requests under CPU load

1 participant