vitest-dev/vitest · error · Error
[vitest] "registerHooks" is not available when running in…
Error message
[vitest] "registerHooks" is not available when running in Vitest.
What it means
Thrown by the stub `Module.registerHooks` static method on the fake CommonJS Module class inside Vitest's vm executor. registerHooks is Node's companion to module.register for setting hook callbacks; Vitest deliberately disables it because it manages its own module pipeline inside workers, and surfaces an explicit error instead of a silent no-op.
Solutions
- Gate the call so it does not run under Vitest: `if (!process.env.VITEST) Module.registerHooks(...)`.
- Mock or exclude the module that performs registration in your test setup.
- Use Vitest-native extension points (server.mode, deps.inline, plugins) instead of Node loader hooks.
- Move the registration into a separate process spawned by the test if the hook behavior must be exercised.
Example fix
// before
import Module from 'node:module'
Module.registerHooks({ load() { /* ... */ } })
// after
import Module from 'node:module'
if (!process.env.VITEST) {
Module.registerHooks({ load() { /* ... */ } })
} Defensive patterns
Strategy: validation
Validate before calling
const isVitest = !!process.env.VITEST
if (!isVitest) {
await import('node:module').then(m => m.registerHooks({ load() { /* ... */ } }))
} Type guard
function shouldSkipModuleRegisterHooks(): boolean {
return !!process.env.VITEST
} Try / catch
try {
Module.registerHooks(hooks)
} catch (e) {
if (String(e?.message).includes('"registerHooks" is not available when running in Vitest')) {
// expected under Vitest
} else throw e
} Prevention
- Guard registerHooks with `!process.env.VITEST` in instrumented libraries.
- Use Vitest plugins or server.deps.inline instead of loader hooks when possible.
- Run loader-dependent code in a spawned child process from tests.
When it happens
Trigger: Code under test (executed through Vitest's vm/commonjs executor) calls `module.registerHooks(...)` or `Module.registerHooks(...)` — typically a library that wires up ESM loader hooks for tracing, instrumentation, or transpilation.
Common situations: Testing instrumentation/tracing SDKs that register hooks at import time; porting code that relied on Node's loader hook APIs into a Vitest suite; running under the default pools that use the vm CommonJS executor.
Related errors
- [vitest] "register" is not available when running in Vitest.
- Cannot import " ": its vm context was torn down.
- Cannot import " ": the test context was torn down.
- Environment " " is not a valid environment. Path " "…
- Environment doesn't provide a valid context. It should be…
AI-assisted analysis of vitest-dev/vitest@1fa9837ec2 (2026-08-11).
Data as JSON: /api/errors/6791000c0951880e.
Report an issue: GitHub.
Appendix: source
Thrown at packages/vitest/src/runtime/vm/commonjs-executor.ts:140
static getSourceMapsSupport = () => ({
enabled: false,
nodeModules: false,
generatedCode: false,
})
static setSourceMapsSupport = () => {
// noop
}
static register = () => {
throw new Error(
`[vitest] "register" is not available when running in Vitest.`,
)
}
static registerHooks = () => {
throw new Error(
`[vitest] "registerHooks" is not available when running in Vitest.`,
)
}
_compile(code: string, filename: string) {
const cjsModule = Module.wrap(code)
const codeCache = executor.codeCache
let script = cjsScriptCache.get(filename)
if (!script) {
const cachedData = codeCache?.get(filename, cjsModule)
// the dynamic import callback is a static function (the executor is
// resolved when it is called), so the compiled script holds no
// per-context state and can be reused by every vm context
try {
script = new vm.Script(cjsModule, {
filename,
cachedData,
importModuleDynamically: activeImportModuleDynamically,View on GitHub (pinned to 1fa9837ec2)