vitest-dev/vitest · error · SyntaxError

require() is not supported in virtual modules. Trying to…

Error message

require() is not supported in virtual modules. Trying to call require("${id}") in ${url}

What it means

When Vitest evaluates a virtual module whose URL is a `data:` URL, it synthesizes a `require` function that unconditionally throws this `SyntaxError` if called. Virtual modules are ESM-only in Vitest's module runner; CommonJS `require()` has no meaningful resolution target inside a data URL.

Solutions

  1. Replace `require(...)` with `import` (static or dynamic `await import(...)`) in the source module.
  2. If the code is in a dependency, check for an ESM build or use `vi.mock`/aliasing to provide an ESM version.
  3. For feature detection, guard the call: `if (typeof require === 'function' && !require.toString().includes('not supported'))` — or simply avoid calling `require` in module-runner-evaluated code.
  4. Ensure the module is loaded as a real file URL (`file://`) rather than inlined as `data:` — check Vite's `optimizeDeps` and plugin `transform` outputs.

Example fix

// before - inside a virtual module
const fs = require('fs')

// after
import fs from 'node:fs'
// or
const fs = await import('node:fs')
Defensive patterns

Strategy: try-catch

Validate before calling

if (url.startsWith('data:') && /\brequire\s*\(/.test(sourceCode)) throw new Error('virtual module uses require — convert to import')

Type guard

null

Try / catch

try { await runner.import(virtualId) } catch (e) { if (/require\(\) is not supported in virtual modules/.test(e.message)) { convertRequireToImport(virtualId); await runner.import(virtualId) } else throw e }

Prevention

When it happens

Trigger: Code inside a virtual/inlined module (transformed into a `data:` URL by Vite, e.g. virtual plugin modules like `virtual:...` that get inlined) contains a literal `require('something')` call. The `createRequire` method at moduleEvaluator.ts:447-454 checks `url.startsWith('data:')` and returns the throwing stub.

Common situations: A dependency authored as CommonJS that gets inlined/virtualized by a plugin; user code that calls `require()` in an ESM-first Vitest context; a Vite virtual module plugin whose generated code uses `require`; modules that feature-detect `typeof require !== 'undefined'` and then call it.

Related errors


AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11). Data as JSON: /api/errors/6101cb9fa1218e77. Report an issue: GitHub.

Appendix: source

Thrown at packages/vitest/src/runtime/moduleRunner/moduleEvaluator.ts:450

      await initModule(...argumentsValues)
    }
    catch (error: unknown) {
      if (!injectCjsGlobals) {
        throw enhanceMissingCjsGlobalsError(error)
      }
      throw error
    }
    finally {
      // moduleExecutionInfo needs to use Node filename instead of the normalized one
      // because we rely on this behaviour in coverage-v8, for example
      this.options.moduleExecutionInfo?.set(options.filename, finishModuleExecutionInfo())
    }
  }

  private createRequire(url: string) {
    if (url.startsWith('data:')) {
      const _require = (id: string) => {
        throw new SyntaxError(`require() is not supported in virtual modules. Trying to call require("${id}") in ${url}`)
      }
      _require.resolve = _require
      return _require
    }
    return this.vm
      ? this.vm.externalModulesExecutor.createRequire(url)
      : createRequire(url)
  }

  private shouldInterop(path: string, mod: any): boolean {
    if (this.options.interopDefault === false) {
      return false
    }
    // never interop ESM modules
    // TODO: should also skip for `.js` with `type="module"`
    return !path.endsWith('.mjs') && 'default' in mod
  }
}

View on GitHub (pinned to 1fa9837ec2)