Skip to content

fix(builders): remove external option from workflow bundle to fix require() errors#830

Closed
technopahadi wants to merge 2 commits intovercel:mainfrom
technopahadi:fix/workflow-vm-require-error
Closed

fix(builders): remove external option from workflow bundle to fix require() errors#830
technopahadi wants to merge 2 commits intovercel:mainfrom
technopahadi:fix/workflow-vm-require-error

Conversation

@technopahadi
Copy link
Copy Markdown
Contributor

Problem

When using packages like ai (Vercel AI SDK) in workflow code, users encounter a runtime error:

  ReferenceError: require is not defined
      at anonymous (../../node_modules/ai/src/telemetry/assemble-operation-name.ts:19:4)
      at Script.runInContext (node:vm:149:12)
      at runInContext (node:vm:301:6)

This regression was introduced in beta.40 when the external option was added to the workflow bundle esbuild config.

Root Cause

The workflow bundle is configured with:

  • format: 'cjs' - because the VM expects CommonJS
  • platform: 'neutral' - because it's neither Node.js nor browser
  • external: this.config.externalPackages || [] - to externalize packages from serverExternalPackages

When a package is marked as external with format: 'cjs', esbuild generates require() calls for those packages:

  var import_api = require("@opentelemetry/api");
  var import_anthropic = require("@ai-sdk/anthropic");

However, the workflow VM created via vm.runInContext() does not have require() defined. Looking at packages/core/src/vm/index.ts, the VM context only provides:

  g.exports = {};
  g.module = { exports: g.exports };

There is no require function, so any externalized package fails at runtime.

Solution

Remove the external option from the workflow bundle esbuild config in createWorkflowsBundle(). This restores the behavior from before beta.40.

Instead of externalizing packages (which generates broken require() calls), we:

  1. Bundle everything into the workflow bundle
  2. Rely on createNodeModuleErrorPlugin() to catch Node.js builtin imports at build time with helpful error messages

Verification

Before fix (beta.40+):

  // In bundled workflow output
  var import_api = require("@opentelemetry/api");  // ❌ Fails at runtime

After fix:

  // In bundled workflow output - package is inlined, no require() call
  // ✅ Works at runtime

Breaking Change?

No. This restores the original behavior from beta.39 and earlier. Users who were affected by the require is not defined error will now have working workflows.

Test Case

  1. Create a workflow that imports from ai package:
  import { convertToModelMessages } from 'ai';

  export async function myWorkflow() {
    'use workflow';
    // ... use convertToModelMessages
  }
  1. Add ai to serverExternalPackages in Next.js config
  2. Run next dev --turbopack -p 3001 or next build and trigger the workflow
  3. Before fix: ReferenceError: require is not defined
  4. After fix: Workflow executes successfully

…uire() errors

When packages are listed in serverExternalPackages and marked as external
in the workflow bundle, esbuild generates require() calls for them (since
format is 'cjs'). However, the workflow VM created via vm.runInContext()
does not have require() defined - it only provides module.exports and exports.

This causes runtime errors like:
  ReferenceError: require is not defined
    at anonymous (../../node_modules/ai/src/telemetry/assemble-operation-name.ts:19:4)

The fix removes the external option from the workflow bundle esbuild config.
Instead of externalizing packages (which generates broken require() calls),
we bundle everything and rely on createNodeModuleErrorPlugin() to catch
Node.js builtin imports at build time with helpful error messages.

This restores the behavior from before beta.40 when the external option
was not present in the workflow bundle config.
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Jan 22, 2026

⚠️ No Changeset found

Latest commit: b133c7e

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link
Copy Markdown
Contributor

vercel bot commented Jan 22, 2026

@technopahadi is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

@pranaygp
Copy link
Copy Markdown
Collaborator

@technopahadi thanks for finding this and fixing it. Could you please resolve the DCO check and include a changeset?

Also it would be awesome to add an e2e test that ensures this doesn't regress again

@pranaygp
Copy link
Copy Markdown
Collaborator

also this change might in turn cause a regression to #731 (@TooTallNate)?

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a workflow bundling regression where externalized packages caused require is not defined errors inside the workflow VM.

Changes:

  • Remove the external option from the workflow esbuild config so that all dependencies are bundled into the workflow bundle.
  • Add detailed inline comments explaining why external is not used for workflows and how createNodeModuleErrorPlugin() is relied on to catch Node.js builtin imports.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Adds e2e test to verify packages in serverExternalPackages work correctly
in workflow code. The test uses lodash.chunk to ensure the workflow bundle
doesn't generate require() calls that would fail in the VM.
@technopahadi
Copy link
Copy Markdown
Contributor Author

@pranaygp Can you review the test?

external: this.config.externalPackages || [],
// NOTE: We intentionally do NOT use the external option here for workflow bundles.
// When packages are marked external with format: 'cjs', esbuild generates require() calls.
// However, the workflow VM (vm.runInContext) does not have require() defined - it only
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removal of external option breaks bundling of pseudo-packages like 'server-only' and 'client-only' in workflow bundles

Fix on Vercel

@technopahadi
Copy link
Copy Markdown
Contributor Author

@pranaygp @TooTallNate ?

@karthikscale3
Copy link
Copy Markdown
Collaborator

Thanks for submitting a PR. This needed a bit more handling and has been fixed with this change

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.

5 participants