Node.js Cannot Find Module (tested)
This error means Node tried to resolve a module path — a local file or an installed package — and found nothing there. The exact wording and the fix differ depending on whether your code uses CommonJS require() or ESM import, which we reproduced separately below.
1. Reproduced: CommonJS, missing local file
require('./doesnotexist')
node:internal/modules/cjs/loader:1568
throw err;
Error: Cannot find module './doesnotexist'
Require stack:
- /tmp/nodemod/[eval]
The "Require stack" tells you which file did the requiring — useful when the failing require() is several modules deep and you need to find the actual source of the bad path.
2. Reproduced: CommonJS, missing installed package
require('some-package-that-is-not-installed')
Error: Cannot find module 'some-package-that-is-not-installed'
Require stack:
- /tmp/nodemod/[eval]
Same error shape as a missing local file — Node's module resolution doesn't distinguish "you misspelled a relative path" from "you forgot to npm install a dependency" in the message itself. Check node_modules/ or package.json's dependencies to tell which one you're looking at.
3. Reproduced: ESM gives a different error class entirely
Using import instead of require() for the exact same missing-file situation produces ERR_MODULE_NOT_FOUND, not plain Error:
import { x } from './does-not-exist.mjs';
node:internal/modules/esm/resolve:272
throw new ERR_MODULE_NOT_FOUND(
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/tmp/nodemod/does-not-exist.mjs'
imported from /tmp/nodemod/bad_missing.mjs
Note it also resolved to a full absolute path, unlike CommonJS which kept the relative path as typed.
4. The gotcha that's unique to ESM: file extensions are mandatory
This is the single most common ESM-specific trigger, and it doesn't happen in CommonJS at all. Importing a real, existing file but leaving off .mjs fails:
// foo.mjs exists right next to this file
import { x } from './foo';
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/tmp/nodemod/foo'
imported from /tmp/nodemod/bad_no_ext.mjs
We confirmed the fix is simply adding the extension back — same file, same directory, only the import line changes:
import { x } from './foo.mjs';
console.log(x);
// -> 1
CommonJS's require('./foo') auto-resolves .js/.json/.node extensions for you; native ESM import deliberately does not, by design (per Node's docs) — relative/absolute specifiers always need the full file extension. This trips up people porting CommonJS code to "type": "module" far more often than an actually missing file does.
5. Checklist before assuming the package is actually missing
- Is it a relative path (starts with
./or../)? Check the file exists at that exact path, and if you're using ESM, that the extension is included. - Is it a bare package name? Check
node_modules/<name>exists and that it's listed inpackage.json— a missingnpm installafter cloning a repo is the single most common real-world cause. - Does the package define an ESM entry point? Some older packages only ship CommonJS; importing them with ESM
importsyntax can fail or behave differently depending on the package's ownexportsfield in itspackage.json, which is a separate (though related) failure mode from a plain missing-module error.
Frequently asked questions
Why does the same missing file produce different error types in require() vs import?
We confirmed this directly: require() throws a plain Error with 'Cannot find module', while ESM import throws Error [ERR_MODULE_NOT_FOUND] — different error classes entirely, even for the identical missing-file scenario, because CommonJS and ESM use separate module resolution algorithms in Node.
I have the file right there and it still says Cannot find module — why?
If you're using ESM (import, or "type": "module" in package.json), check whether you left off the file extension. We reproduced this exactly: import './foo' failed while import './foo.mjs' (the identical file) succeeded. CommonJS require() doesn't have this requirement.
Does Cannot find module always mean a missing npm install?
No — we reproduced the identical error message for a missing local file (a relative path typo) and a missing installed package. Check whether the path starts with ./ or ../ (a local file problem) versus a bare name (an npm install problem) before assuming which one it is.
What does the 'Require stack' section tell me?
It lists the chain of files that led to the failing require() call, which is useful when the bad import is several modules deep — you can trace exactly which file issued the require that actually failed, rather than guessing from the entry point.
Is this the same as webpack's 'Module not found' or TypeScript's TS2307?
No — those are build-time errors from a bundler or compiler resolving modules ahead of execution. This guide covers Node's own runtime module resolution (require()/import actually executing), which is a separate resolution step with its own rules and can fail even when a bundler build succeeded.
Written with AI assistance. Measured on 2026-10-03 with Node 24.21.0, running real CommonJS (require) and ESM (import) scripts against missing files and packages. Every error message below is copy-pasted output, not paraphrased. PlainHeaders is our extension; Node is free.