ERR_REQUIRE_CYCLE_MODULE
Node.jsWARNINGNotableModuleHIGH confidence

Circular require() dependency detected in CJS/ESM interop

Production Risk

Circular ESM/CJS interop can produce undefined exports, causing silent failures in production.

What this means

Thrown when Node.js detects a circular dependency while using require() to load an ES module that itself (directly or indirectly) requires the original module back. Because ESM is evaluated synchronously in the require() interop path introduced in Node.js 22, a cycle can produce an incomplete module binding.

Why it happens
  1. 1Module A requires Module B which requires Module A before A has finished initialising
  2. 2Mixing CJS require() and ESM import in a circular graph
  3. 3Barrel/index files that re-export everything from sibling modules forming a cycle
How to reproduce

Occurs during module loading when require() resolves an ESM file that re-requires the original caller.

trigger — this will error
trigger — this will error
// a.cjs
const b = require('./b.mjs');
module.exports = { a: 1 };

// b.mjs  — creates the cycle
import { a } from './a.cjs';
export const b = a + 1;

expected output

node:internal/modules/esm/translators:Error [ERR_REQUIRE_CYCLE_MODULE]: Require cycle detected

Fix 1

Extract shared code into a third module

WHEN When two modules depend on each other

Extract shared code into a third module
// shared.mjs
export const sharedValue = 1;

// a.mjs
import { sharedValue } from './shared.mjs';

// b.mjs
import { sharedValue } from './shared.mjs';

Why this works

Breaking the cycle by introducing a dependency-free shared module eliminates the circular reference.

Fix 2

Use lazy imports inside functions

WHEN When the circular value is only needed at call time, not at module load time

Use lazy imports inside functions
// b.mjs
export async function getB() {
  const { a } = await import('./a.mjs');
  return a + 1;
}

Why this works

Dynamic import() is deferred until the function executes, by which point all modules are fully initialised.

Code examples
Triggerjs
// a.cjs
const b = require('./b.mjs');
module.exports = { a: 1 };

// b.mjs  — creates the cycle
import { a } from './a.cjs';  // this triggers ERR_REQUIRE_CYCLE_MODULE
Handle in try/catchjs
try {
  // operation that may throw ERR_REQUIRE_CYCLE_MODULE
  riskyOperation()
} catch (err) {
  if (err.code === 'ERR_REQUIRE_CYCLE_MODULE') {
    console.error('ERR_REQUIRE_CYCLE_MODULE:', err.message)
  } else {
    throw err
  }
}
Defensive pattern to avoid itjs
// Validate inputs before calling the operation
function safe_err_require_cycle_module(...args) {
  // validate args here
  return performOperation(...args)
}
What not to do

Ignore the warning and ship

Incomplete bindings cause subtle runtime bugs that are hard to trace.

Same error in other languages
Sources
Official documentation ↗

Node.js Error Codes Documentation

Content generated with AI assistance and reviewed for accuracy. Found an error? hello@errcodes.dev

← All Node.js errors