Repository navigation
Description
TL;DR
@vercel/sandbox ships "use step" directives in its published dist. When a Next app using @workflow/next has the SDK anywhere in the module graph of /.well-known/workflow/v1/step, the workflow SWC plugin rewrites the SDK's classes — which are anonymous class expressions — and emits a reference to a binding that does not exist. The build fails during "Collecting page data".
Both packages are Vercel's, so this looks like an interop defect rather than a misuse.
Error
Error: Failed to collect configuration for /.well-known/workflow/v1/step
at ignore-listed frames {
[cause]: ReferenceError: AnonymousClass is not defined
at ../../node_modules/@vercel/sandbox/dist/filesystem.js (app/.well-known/workflow/v1/step/route.js:6207:84)
at <unknown> (app/.well-known/workflow/v1/step/route.js:10:54)
at module evaluation (app/.well-known/workflow/v1/step/route.js:11749:1)
6205 | }
6206 | };
> 6207 | registerStepFunction29("step//@vercel/sandbox@3.1.0//AnonymousClass#readFile", AnonymousClass.prototype["readFile"]);
| ^
6208 | registerStepFunction29("step//@vercel/sandbox@3.1.0//AnonymousClass#writeFile", AnonymousClass.prototype["writeFile"]);
6209 | registerStepFunction29("step//@vercel/sandbox@3.1.0//AnonymousClass#appendFile", AnonymousClass.prototype["appendFile"]);
6210 | registerStepFunction29("step//@vercel/sandbox@3.1.0//AnonymousClass#mkdir", AnonymousClass.prototype["mkdir"]);
}
> Build error occurred
Error: Failed to collect page data for /.well-known/workflow/v1/step
Suspected cause
@vercel/sandbox/dist/filesystem.js declares its classes as anonymous class expressions assigned to a variable:
var SandboxStats = class { … };
var SandboxDirent = class { … };
var FileSystem = class { … }; // 20 "use step" directives in this fileThe loader transforms any file whose source carries a directive, including files under node_modules (@workflow/next/dist/loader.js, patterns.hasDirective). For a class expression the plugin appears to fall back to the placeholder name AnonymousClass instead of the variable the class is assigned to, then emits AnonymousClass.prototype["readFile"]. Nothing declares AnonymousClass, so the module throws on evaluation.
Using the assigned variable name (FileSystem), or skipping registration when no binding can be resolved, would both avoid this.
Reproduction
In a Next app with withWorkflow configured, import @vercel/sandbox from any module reachable from a "use step" function, then run next build. The failure is at "Collecting page data", not at compile.
Environment
@vercel/sandbox3.1.0@workflow/next4.1.2- next 16.3.1, Turbopack
- Node 24, pnpm 10.32.1, macOS arm64
Already ruled out
- Upgrading the SDK. 3.0.1, 3.1.0, 3.2.0 and 3.2.1 all ship
var FileSystem = class— verified by unpacking each tarball. serverExternalPackages: ["@vercel/sandbox"]. Same failure; the loader rewrites the source before externalisation applies.- A non-literal import specifier, to keep the SDK out of the graph. Turbopack folds the constant, then fails
Module not found: Can't resolve '@vercel/sandbox'. - A
withWorkflowexclusion option. None found — the only documented option isworkflows.local.port.
Questions
- Is a fix planned, and on which side — the SWC plugin's naming of class expressions, or the SDK's published dist shape?
- Is there a supported way to exclude a package from the workflow step transform?
Impact
We can only reach @vercel/sandbox from non-Next runtimes today; our Next app's workflow routes cannot use it at all. That blocks moving our sandbox workload onto Vercel Sandbox, since most of our code-execution entrypoints run inside workflow steps.
Possibly related, though both are different failure modes: #3051 (directive-free modules sent through SWC on the Nitro builder) and #3900 (valid use step directives missed after raw backticks). Both suggest the directive-detection and transform path is where this belongs.
Activity
luca-primefold commentedon Sep 4, 2026
Vercel Support routed this here rather than answering it. I opened a support case for the same defect and it was closed as out of paid-support scope, because
@workflow/nextis open source, with this issue named as "the best place to continue the conversation and receive further support" and a note that it was "shared internally with our engineering team for visibility" — explicitly with no ETA. So this issue is the only channel; flagging that in case triage labels are what it is waiting on.Question 2 above is the one that decides what we build, so narrowing it: is there any supported way to keep a
node_modulespackage out of the step transform — awithWorkflowoption, an env var, or a convention the loader honours? A plain "no" is a genuinely useful answer. We would then put the SDK behind an HTTP boundary so it is only ever loaded in a non-Next runtime, and I would rather not build that if an exclusion mechanism is on the way.Offering the work either way:
patterns.hasDirectivein@workflow/next/dist/loader.jslooks like the single place a package-level skip would go, and resolving a class expression to its assigned variable name (FileSystem) instead of theAnonymousClassplaceholder looks similarly contained in the plugin. Happy to open a PR against whichever side you would take.TooTallNate commentedon Sep 4, 2026
Hey Luca, so this seems to be a regression in either the Workflow SDK compiler or
@vercel/sandbox, not sure which yet, but the"use step"directives are intentionally in the sandbox package and are meant to be transformed by the Workflow SDK compiler, so skip is not the correct solution - resolving to the assigned variable name sounds more reasonable. I'll be looking into this today, but also happy to take a look at a PR if you get to it before me.TooTallNate commentedon Sep 4, 2026
@luca-primefold Can you provide a repro repository? I am having trouble replicating your error.
fix(swc-plugin): register class expressions via an IIFE instead of by…
fix(swc-plugin): register class expressions via an IIFE instead of by…
fix(swc-plugin): register class expressions via an IIFE instead of by…
TooTallNate commentedon Sep 10, 2026
PR #3971 added hardening for classes tangentially related to this issue, but since the trigger is via an
overridewith a old version of the@workflow/builderspackage and it does not reproduce against latest stable, then I think we can close this.