vitest-dev/vitest · error · Error

[vitest] "register" is not available when running in Vitest.

Error message

[vitest] "register" is not available when running in Vitest.

What it means

Thrown by the stub `Module.register` static method on the fake CommonJS Module class used inside Vitest's vm executor (commonjs-executor.ts). Node's real `module.register()` registers an ESM loader hook chain; Vitest provides its own module system inside workers, so that API is intentionally disabled and surfaces this explicit error rather than silently doing nothing.

Solutions

  1. Avoid calling `module.register` in code that runs under Vitest; gate it behind an environment check (e.g. only register when not in a Vitest worker).
  2. Use Vitest's own loader/server.mode or `server.deps.inline` mechanisms instead of a self-registering loader.
  3. Mock or stub the module that calls `register` in your test setup if its loader behavior is not under test.
  4. If the registration is essential, run that code in a child process spawned from the test rather than inside the Vitest module system.

Example fix

// before
import Module from 'node:module'
Module.register('./my-loader.mjs')

// after — skip registration under Vitest
import Module from 'node:module'
if (!process.env.VITEST) {
  Module.register('./my-loader.mjs')
}
Defensive patterns

Strategy: validation

Validate before calling

// Skip module.register when running under Vitest
const isVitest = !!process.env.VITEST
if (!isVitest) {
  await import('node:module').then(m => m.register('./loader.mjs'))
}

Type guard

function shouldSkipModuleRegister(): boolean {
  return !!process.env.VITEST
}

Try / catch

try {
  Module.register('./loader.mjs')
} catch (e) {
  if (String(e?.message).includes('"register" is not available when running in Vitest')) {
    // expected under Vitest; fall through
  } else throw e
}

Prevention

When it happens

Trigger: Code under test (loaded via Vitest's vm/commonjs executor) calls `module.register(...)` or `Module.register(...)` — e.g. a library that self-registers a custom ESM loader, or application code calling the module register API at import time.

Common situations: Testing a package that uses `module.register` to hook imports (e.g. for instrumentation, tracing, or tsx-style loading); running such code under Vitest's default forks/threads pools which use the vm-based CommonJS executor.

Related errors


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

Appendix: source

Thrown at packages/vitest/src/runtime/vm/commonjs-executor.ts:134

        }

        const _require = Module.createRequire(this.id)
        requiresCache.set(this, _require)
        return _require
      }

      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

View on GitHub (pinned to 1fa9837ec2)