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
- Replace `require(...)` with `import` (static or dynamic `await import(...)`) in the source module.
- If the code is in a dependency, check for an ESM build or use `vi.mock`/aliasing to provide an ESM version.
- 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.
- 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
- Author virtual-module plugin output as pure ESM (use `import`).
- Avoid `typeof require` feature-detection that falls through to a `require()` call.
- Prefer `createRequire(import.meta.url)` only in real `file://` modules, never in `data:` URLs.
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
- Benchmark provider loaded from
- Cannot import " ": its vm context was torn down.
- Cannot spy on export
- createNodeImportMeta is not supported in this version of…
- Custom reporter loaded from
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)