denoland/deno · error · Error

ERR_VM_MODULE_DIFFERENT_CONTEXT

ERR_VM_MODULE_DIFFERENT_CONTEXT

Error message

Linked modules must use the same context

What it means

Thrown by vm.Module#link() when the linker returns a module that was created against a different context than the module being linked. Every module records the `context` from its options object in kContext; link() enforces `m.context === this[kContext]` (vm.js:682) because a V8 module graph must be instantiated within a single context.

Source

Thrown at ext/node/polyfills/vm.js:683

    const linkerPromises = [];
    for (let i = 0; i < requests.length; i++) {
      const { specifier, attributes } = requests[i];
      ArrayPrototypePush(specifiers, specifier);
      const p = PromiseResolve(
        linker(specifier, this, { attributes, assert: attributes }),
      );
      ArrayPrototypePush(linkerPromises, p);
    }
    const resolvedModules = await SafePromiseAll(linkerPromises);

    const wraps = [];
    for (let i = 0; i < resolvedModules.length; i++) {
      const m = resolvedModules[i];
      if (!isModule(m)) {
        throw new ERR_VM_MODULE_NOT_MODULE();
      }
      if (m.context !== this[kContext]) {
        throw new ERR_VM_MODULE_DIFFERENT_CONTEXT();
      }
      ArrayPrototypePush(wraps, m[kWrap]);
    }

    // Record this module's resolutions before recursing so a dependency that
    // imports back into this module finds it already in `visited`.
    op_vm_module_link(this[kWrap], specifiers, wraps);

    for (let i = 0; i < resolvedModules.length; i++) {
      await resolvedModules[i][kLinkGraph](linker, visited);
    }
  }

  evaluate(options = { __proto__: null }) {
    try {
      validateObject(options, "options");
      const status = op_vm_module_get_status(this[kWrap]);
      // Allow evaluate from linked (2), evaluating (3), evaluated (4), errored (5).

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Pass the exact same context value to every module in the graph: derive it inside the linker from `mod.context` (the second link() argument)
  2. If the root module has no context, omit `context` in dependency module options too (undefined must match undefined)
  3. Key any linker-side module cache by `${specifier}\0${context ?? 'default'}` so modules are never reused across contexts
  4. Re-create cached dependency modules when the incoming module's context differs from the cached one

Example fix

// before
const ctx = vm.createContext({});
const root = new vm.SourceTextModule(code); // no context
root.link(async (spec) => new vm.SourceTextModule(files[spec], { context: ctx })); // ERR_VM_MODULE_DIFFERENT_CONTEXT
// after
const ctx = vm.createContext({});
const root = new vm.SourceTextModule(code, { context: ctx });
root.link(async (spec, mod) =>
  new vm.SourceTextModule(files[spec], { context: mod.context }));
Defensive patterns

Strategy: type-guard

Validate before calling

const deps = await Promise.all(requests.map((r) => linker(r.specifier, mod)));
for (const d of deps) {
  if (d.context !== mod.context) throw new Error(`context mismatch for ${d.identifier}`);
}

Type guard

const sameContext = (a, b) => a.context === b.context; // undefined must match undefined

Try / catch

mod.link(linker).catch((e) => {
  if (e.code === 'ERR_VM_MODULE_DIFFERENT_CONTEXT') {
    // rebuild dependency modules with mod.context, then retry with a FRESH root module
  } else throw e;
});

Prevention

When it happens

Trigger: Creating the root module with `new vm.SourceTextModule(code)` (no context) but returning dependencies built with `new vm.SourceTextModule(code, { context: someContext })`, or vice versa; using two different context objects from two vm.createContext() calls for root and dependencies; sharing a cached module created for context A while linking a graph rooted in context B.

Common situations: A linker that caches modules in a Map keyed only by specifier, ignoring which context they were created for, then reuses that cache for a second run under a fresh vm.createContext(); tutorials that create the dependency inside `vm.createContext(...)` while the root module is context-less; refactoring code so only some modules receive options.context.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/e8acb954584a6ce8. Report an issue: GitHub.