fix(eve): self-hosted workflow queue handler + world version-compat guard#308
Merged
Conversation
`eve start` previously gated the direct queue→bundle handler binding on
`nitro.options.dev`, so a self-hosted (non-Vercel) production build with a
configured custom workflow world never registered it. Jobs the world
dispatched to the flow route came back `400 {"error":"Unhandled queue"}`
and runs sat in `pending` forever, with `eve dev --no-ui` as the only
workaround.
The real axis is who drives the queue: the local/configured world drives
it in-process in both `eve dev` and self-hosted `eve start`, whereas Vercel
dispatches through its managed queue trigger over HTTP. Register the binding
whenever the local world drives the queue — dev, or a non-Vercel build with
a configured world — and never for Vercel-managed deploys, preserving that
path exactly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
`pnpm add @workflow/world-postgres` resolves to npm latest (4.x), which is incompatible with the `@workflow/*` 5.0.0-beta line eve bundles. The mismatch surfaced as a cryptic `ZodError: invalid_union` deep in workflow replay, with no hint about versions. Add a boot-time, best-effort compatibility guard: when a custom world is configured, eve reads the world's declared `@workflow/core` (or `@workflow/world`) line and compares it against the line from eve's own package.json (single source of truth, via `resolveExpectedWorkflowVersion`). On a definite major / prerelease-line mismatch it throws an actionable error naming the fix; when versions can't be determined it no-ops to avoid false-positive boot failures. The comparison lives in a pure, exported, unit-tested helper (`assertWorkflowWorldCompatibility`); no new runtime dependency is added. The deeper, fully version-aware fix is being proposed upstream in `@workflow/core`. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Pranay Prakash <pranay.gp@gmail.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
Bundle + Package Summary:
|
| Area | Metric | Baseline | Current | Delta |
|---|---|---|---|---|
| Package | Packed tarball | 3.43 MB | 3.43 MB | +1.7 kB |
| Package | Unpacked publish size | 12.45 MB | 12.45 MB | +5.9 kB |
| Package | Installed footprint | 52.43 MB | 52.44 MB | +5.9 kB |
| Package | Published files | 2314 | 2316 | +2 |
| Package | Installed files | 5522 | 5524 | +2 |
| Runtime | Unique function payloads | 2 | 2 | 0 |
| Runtime | Total function bytes | 9.62 MB | 9.62 MB | -176 B ✅ |
| Runtime | Public routes | 9 | 9 | 0 |
Changed function payloads vs main (293d003) (2)
| Function | Status | Baseline | Current | Delta | Route changes |
|---|---|---|---|---|---|
functions/__server.func |
changed | 3.98 MB | 3.98 MB | -144 B ✅ | none |
functions/.well-known/workflow/v1/flow.func |
changed | 5.64 MB | 5.64 MB | -32 B ✅ | none |
Build Metadata
- Preset:
vercel - Nitro:
nitro@3.0.260610-beta - Output directory:
apps/fixtures/weather-agent/.vercel/output - Build metadata timestamp: 2026-06-25T20:46:59.143Z
- Route aliases: 9 public, 1 internal (10 total aliases)
- Vercel routes in config: 10
- Severity legend: 🔴 dominant/large, 🟠 notable, 🟡 watch, ⚪ small
Package Drill-Down
Package Details
- Package:
eve@0.14.0 - Package directory:
packages/eve - Tarball: 3.43 MB (
eve-0.14.0.tgz) - Unpacked payload: 12.45 MB across 2316 published files
- Installed footprint: 52.44 MB across 5524 installed files
- Installed root package: 11.18 MB
- Installed dependencies: 41.26 MB
- Runtime dependencies: 1
- Peer dependencies: 12 (11 optional)
Installed footprint is measured from an isolated temporary npm install of the packed tarball.
Heavy installed dependencies
@rolldown/binding-linux-x64-gnu: 20.26 MB (38.6%)eve: 11.18 MB (21.3%)ai: 6.26 MB (11.9%)zod: 5.04 MB (9.6%)nitro: 2.41 MB (4.6%)
Publish payload breakdown
Published file size
🟠 dist/src/compiled/experimental-ai-sdk-code-mo... [####....................] 1.51 MB 12.1%
🟡 dist/src/compiled/@workflow/core/runtime.js [##......................] 788.4 kB 6.3%
🟡 dist/src/compiled/@vercel/sandbox/index.js [##......................] 632.0 kB 5.1%
🟡 dist/src/compiled/@chat-adapter/slack/index.js [#.......................] 438.4 kB 3.5%
🟡 dist/src/compiled/_chunks/workflow/attribute-... [#.......................] 371.6 kB 3.0%
🔴 Other published files [########################] 8.72 MB 70.0%
Installed footprint breakdown
Installed package size
🔴 @rolldown/binding-linux-x64-gnu [########################] 20.26 MB 38.6%
🔴 eve [#############...........] 11.18 MB 21.3%
🔴 ai [#######.................] 6.26 MB 11.9%
🔴 zod [######..................] 5.04 MB 9.6%
🟠 nitro [###.....................] 2.41 MB 4.6%
🟡 rolldown [#.......................] 771.7 kB 1.5%
🔴 Other installed packages [########................] 6.52 MB 12.4%
Runtime dependencies (1)
| Package | Range | Notes |
|---|---|---|
nitro |
3.0.260610-beta |
Peer dependencies (12)
| Package | Range | Notes |
|---|---|---|
@opentelemetry/api |
^1.0.0 |
optional peer |
@sveltejs/kit |
^2.0.0 |
optional peer |
ai |
catalog: |
|
braintrust |
^3.0.0 |
optional peer |
just-bash |
^3.0.0 |
optional peer |
microsandbox |
^0.5.0 |
optional peer |
next |
^16.0.0 |
optional peer |
nuxt |
^4.0.0 |
optional peer |
react |
^19.0.0 |
optional peer |
svelte |
^5.0.0 |
optional peer |
vite |
^8.0.0 |
optional peer |
vue |
^3.5.0 |
optional peer |
Function Drill-Down
Payload Size Graph
Unique function payload size and share of total
🔴 functions/.well-known/workflow/v1/flow.func [########################] 5.64 MB 58.6%
🔴 functions/__server.func [#################.......] 3.98 MB 41.4%
Top Function Payloads
🟠 functions/.well-known/workflow/v1/flow.func • 1 public route • 5.64 MB
| Metric | Value |
|---|---|
| Public routes | /.well-known/workflow/v1/flow |
| Runtime | nodejs24.x |
| Handler | index.mjs |
| Payload | 5.64 MB |
| Function files | 5.64 MB across 26 files |
| Traced dependencies | 0 B |
| Signal | 🟠 Bundled file __eve_nitro_handler__.mjs is 1.87 MB (33.2%) |
🟠 🔎 Dependency Analysis
📦 Bundled files:
Bundled file size
🟠 __eve_nitro_handler__.mjs [########################] 1.87 MB 33.2%
🟠 _chunks/runtime.mjs [#############...........] 975.4 kB 17.3%
🟡 _chunks/sandbox.mjs [##########..............] 766.0 kB 13.6%
🟡 _chunks/attribute-changes-DUxG-Gic.mjs [######..................] 473.2 kB 8.4%
🟡 _libs/@ai-sdk/gateway+[...].mjs [#####...................] 413.5 kB 7.3%
🟠 Other bundled files [###############.........] 1.14 MB 20.2%
🧾 Vercel Config
{
"handler": "index.mjs",
"launcherType": "Nodejs",
"shouldAddHelpers": false,
"supportsResponseStreaming": true,
"runtime": "nodejs24.x",
"environment": {
"NODE_OPTIONS": "--experimental-require-module"
},
"maxDuration": "max",
"experimentalTriggers": [
{
"type": "queue/v2beta",
"topic": "__eve_wkf_workflow_*",
"consumer": "default",
"retryAfterSeconds": 5,
"initialDelaySeconds": 0
}
]
}🟠 functions/__server.func • 8 public routes, 1 internal alias • 3.98 MB
| Metric | Value |
|---|---|
| Public routes | //eve/v1/callback/[token]/eve/v1/connections/[name]/callback/[token]/eve/v1/health/eve/v1/info/eve/v1/session/eve/v1/session/[sessionId]/eve/v1/session/[sessionId]/stream |
| Internal aliases | /__server |
| Runtime | nodejs24.x |
| Handler | index.mjs |
| Payload | 3.98 MB |
| Function files | 3.98 MB across 21 files |
| Traced dependencies | 0 B |
| Signal | 🟠 Bundled file index.mjs is 1.51 MB (37.9%) |
🟠 🔎 Dependency Analysis
📦 Bundled files:
Bundled file size
🟠 index.mjs [########################] 1.51 MB 37.9%
🟠 _chunks/runtime.mjs [##############..........] 883.8 kB 22.2%
🟠 _chunks/sandbox.mjs [############............] 766.0 kB 19.2%
🟡 _chunks/attribute-changes-DUxG-Gic.mjs [#######.................] 448.9 kB 11.3%
⚪ _libs/zod.mjs [##......................] 114.2 kB 2.9%
🟡 Other bundled files [####....................] 258.8 kB 6.5%
🧾 Vercel Config
{
"handler": "index.mjs",
"launcherType": "Nodejs",
"shouldAddHelpers": false,
"supportsResponseStreaming": true,
"runtime": "nodejs24.x"
}
Contributor
Author
|
Part of the self-hosted workflow-world improvements (from a self-hosting writeup). Pairs with the docs in #306 (reverse-proxy |
AndrewBarba
approved these changes
Jun 25, 2026
This was referenced Jun 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two related fixes for the self-hosted Postgres workflow-world story. Pairs with the sibling docs PR on branch
pgp/eve-self-host-workflow-docs.FIX 1 —
eve startregisters the workflow queue handler for self-hosted (non-Vercel) productionBug: With a custom/local workflow world configured (e.g.
@workflow/world-postgres) and the documented production patheve build && eve start, the direct queue→bundle handler binding was never registered. Jobs the world dispatched to/.well-known/workflow/v1/flowcame back400 {"error":"Unhandled queue"}and runs sat inpendingforever. The only workaround waseve dev --no-ui, which is semantically wrong for production.Root cause: In
packages/eve/src/internal/nitro/host/configure-nitro-routes.tsthedirectHandlerEntrieswere gated onnitro.options.dev. The HTTP flow route is registered in production, but its queue→bundle binding (generated only whendirectHandlerEntriesis non-empty) was not. The real axis is not dev-vs-prod; it is who drives the queue: the local/configured world drives it in-process in botheve devand self-hostedeve start, whereas Vercel dispatches through its managed queue trigger over HTTP.Fix: Register the binding whenever the local world drives the queue —
dev, OR a non-Vercel build (!isVercelBuildEnvironment()) with a configured custom world (manifest.config.experimental.workflow.worldset) — and never for Vercel-managed deploys.isVercelBuildEnvironment()is now exported frompackages/eve/src/internal/application/paths.ts. The Vercel path is preserved exactly (binding still absent whenVERCELis set at build).Final gate condition:
The added custom-world clause keeps non-custom-world production builds byte-for-byte identical to today (no binding); only custom-world self-hosted prod — the bug — changes.
End-to-end wiring question (resolved)
I traced
@workflow/world-local's queue dispatch (queue.js): if a direct handler is registered for the queue prefix it calls it in-process and short-circuits the HTTP path entirely; only when no direct handler exists does it fall back tofetch(${baseUrl}/.well-known/workflow/v1/...)wherebaseUrlcomes fromWORKFLOW_LOCAL_BASE_URL/PORT. So registering the binding (FIX 1) is the complete fix for self-hosted runs and does not require theinstallWorkflowLocalQueueEnvironmentenv wiring used byeve dev— the world never reaches the HTTP fallback. As a belt-and-suspenders,startProductionServeralready setsPORTon the spawned child, so even the fallback would resolvehttp://localhost:${PORT}. Full end-to-end validation against a real Postgres world remains out of scope for unit tests (no Postgres in CI); the in-process dispatch path is exercised by the existing/added unit tests.Tests (FIX 1)
does not register direct workflow queue handlers in production builds→...for Vercel production builds(stubsVERCEL=1viavi.stubEnv).registers direct workflow queue handlers for self-hosted production builds with a configured world.does not register direct workflow queue handlers for self-hosted production builds without a configured world.beforeEachnowvi.unstubAllEnvs()to keep env from leaking;paths.jsis mocked to a realisVercelBuildEnvironmentthat readsprocess.env.VERCEL, sovi.stubEnvstill drives behavior while avoiding the heavy import graph.FIX 2 — boot-time workflow world version-compat guard
Trap:
pnpm add @workflow/world-postgresresolves to npmlatest(4.x), incompatible with the@workflow/*5.0.0-beta line eve bundles (@workflow/core@5.0.0-beta.24). The mismatch surfaced as a crypticZodError: invalid_uniondeep in workflow replay.Fix: A simple, low-risk eve-side guard that fails loud and early. New pure, exported, doc-commented helper
assertWorkflowWorldCompatibility(packages/eve/src/internal/workflow/world-compatibility.ts) takes already-parsed JSON and throws only on a definite major / prerelease-line mismatch; it no-ops when the world declares no@workflow/*dep or the range is unparseable (avoids false-positive boot failures). The expected line comes from a single source of truth — eve's ownpackage.jsonvia newresolveExpectedWorkflowVersion()inpackages/eve/src/internal/application/package.ts— so no version is hardcoded. The world package name is threaded from the generated bootstrap (compiled-artifacts.ts) intoinstallConfiguredWorkflowWorld({ module, packageName }), which reads the world'spackage.jsonviacreateRequire(import.meta.url).resolve(...)and calls the pure helper. No new runtime dependency (no semver lib; a tiny major/prerelease-line parse). The deeper, fully version-aware fix is being proposed upstream in@workflow/corevia a separate issue.Example thrown message:
Configured Workflow world "@workflow/world-postgres" targets @workflow/core 4.x, but this eve release requires the @workflow/core 5.0.0-beta line. Install a matching world, e.g. \pnpm add @workflow/world-postgres@5.0.0-beta.24`.`Tests (FIX 2)
world-compatibility.test.ts(pure helper): older major → throws actionable message (asserts name + line + install command); same prerelease line / caret range → passes; falls back to@workflow/worldand readspeerDependencies; no@workflow/*dep / unparseable range / unparseable expected → no-op.package.test.ts:resolveExpectedWorkflowVersionreads eve's@workflow/coreline.compiled-artifacts.test.ts: bootstrap body assertion updated to includepackageName.Files changed
packages/eve/src/internal/nitro/host/configure-nitro-routes.ts— new gate; importisVercelBuildEnvironment.packages/eve/src/internal/application/paths.ts— exportisVercelBuildEnvironment(+ doc).packages/eve/src/internal/nitro/host/configure-nitro-routes.test.ts— retargeted/added tests; env hygiene; mockpaths.js.packages/eve/src/internal/workflow/world-compatibility.ts— new pure helper.packages/eve/src/internal/workflow/world-compatibility.test.ts— new helper tests.packages/eve/src/internal/workflow/configure-world.ts— boot-time compat check; threadpackageName.packages/eve/src/internal/application/package.ts— newresolveExpectedWorkflowVersion.packages/eve/src/internal/application/package.test.ts— test for the above.packages/eve/src/internal/application/compiled-artifacts.ts— passpackageNameto bootstrap call.packages/eve/src/internal/application/compiled-artifacts.test.ts— updated bootstrap assertion..changeset/self-host-workflow-runtime.md— patch changeset.Validation
pnpm install --frozen-lockfile✓pnpm --filter eve typecheck✓oxlint packages/eve/src✓ (clean) ·pnpm guard:invariants✓🤖 Generated with Claude Code