Skip to content

@vercel/sandbox breaks the Next build: SWC plugin emits AnonymousClass.prototype[...] for the SDK's anonymous class expressions #3929

Description

@luca-primefold

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 file

The 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/sandbox 3.1.0
  • @workflow/next 4.1.2
  • next 16.3.1, Turbopack
  • Node 24, pnpm 10.32.1, macOS arm64

Already ruled out

  1. 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.
  2. serverExternalPackages: ["@vercel/sandbox"]. Same failure; the loader rewrites the source before externalisation applies.
  3. 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'.
  4. A withWorkflow exclusion option. None found — the only documented option is workflows.local.port.

Questions

  1. Is a fix planned, and on which side — the SWC plugin's naming of class expressions, or the SDK's published dist shape?
  2. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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