Next.js

Fix Cannot find module 'caniuse-lite/dist/unpacker/agents'

Why npm install, npm ls and update-browserslist-db all report a healthy tree while the error stays, and the one reinstall that actually puts the missing files back.

Mahdi Ben RhoumaMahdi Ben Rhouma
8 min read

TL;DR#

browserslist loads its browser data with require('caniuse-lite/dist/unpacker/agents'). The error means that file is absent from node_modules. The stubborn case is an incomplete install, where the caniuse-lite folder exists but its dist directory does not: npm install, npm ls and npx update-browserslist-db@latest all accept that folder and leave it alone. npm ci, which removes node_modules before installing from package-lock.json, puts the files back. The popular npm i caniuse-lite only works when it happens to install a different version.

The error#

The question on Stack Overflow comes from npx create-react-app on Node 14.15.3 and npm 6.14. The same message appears in Vue projects, in Next.js and in Vite projects that use the Babel React plugin, because all of them reach browserslist somewhere in the tree. On Node 22 the output contains these lines:

text
Error: Cannot find module 'caniuse-lite/dist/unpacker/agents'
Require stack:
- /work/app/node_modules/browserslist/index.js
- /work/app/[eval]

The first line of the require stack names the package that asked for the file. In a real project it is usually browserslist, reached through @babel/preset-env, autoprefixer or Next.js.

Why it happens#

caniuse-lite is the compressed browser-support dataset behind browserslist. The third line of browserslist's index.js is:

js
var agents = require('caniuse-lite/dist/unpacker/agents').agents

That require runs as soon as browserslist is loaded, before any of your config is read. Everything that targets browsers depends on it: @babel/helper-compilation-targets (used by @babel/preset-env) and autoprefixer both list browserslist as a dependency on the npm registry. Next.js ships its own compiled copy: the published next@16.4.0 file dist/compiled/browserslist/index.js contains this module:

text
946:e=>{"use strict";e.exports=require("caniuse-lite/dist/unpacker/agents")}

That compiled copy does not bundle the data: it loads it from node_modules. The next package also lists caniuse-lite as a direct dependency on the npm registry.

So the error is not about your code or your browserslist query. Node found a caniuse-lite folder, or no folder at all, and that folder has no dist/unpacker/agents.js. The caniuse-lite maintainer's answer to a sibling report (caniuse-lite #39, where dist/unpacker/agents.js itself failed to load ../../data/browsers) was that the node_modules folder was broken, and that the fix was to remove it and the npm cache, then install the dependencies again.

How a folder ends up half-extracted is not documented for the original December 2020 case. Two later reports describe the same state. In a Next.js project's fix, the folder held only package.json, LICENSE and README.md. In another case, a sandbox image shipped a pre-built node_modules and the install step was skipped.

Reproduce it, and see what does not fix it#

The state is easy to simulate. The following was run on 10 October 2026 in the official node:22-bookworm Docker image (Node v22.23.3, npm 10.9.9), with browserslist@4.29.3, which pulled caniuse-lite@1.0.30001815:

bash
npm init -y
npm install browserslist@4.29.3
rm -rf node_modules/caniuse-lite/dist
node -e "console.log(require('browserslist')('last 1 Chrome version'))"

The require fails with the error above. Then the usual reflexes, one at a time, from that broken tree.

Plain npm install does nothing:

text
up to date in 418ms

The folder still has no dist, and the error stays.

npm ls reports a clean tree and exits with code 0:

text
`-- browserslist@4.29.3
  `-- caniuse-lite@1.0.30001815
npm ls exit: 0

npx update-browserslist-db@latest, the command browserslist itself recommends when its data is old, sees a current version and stops there:

text
Installed version:       1.0.30001815
caniuse-lite is up to date

It still prints caniuse-lite has been successfully updated, followed by Problem with browser list retrieval. — a sign of the broken folder — yet the folder is untouched and the error stays. All three accepted a folder that still had its package.json and data directory but no dist.

The most-voted answer, npm i caniuse-lite, also printed up to date in 634ms when the broken folder already held the latest release. The error stayed, and caniuse-lite was now written into package.json as a direct dependency.

Fix#

1. Reinstall from the lockfile with npm ci#

From the project root, with package-lock.json present:

bash
npm ci

On the same broken tree, with node_modules left in place, npm ci printed added 8 packages in 2s, dist was back, and browserslist returned [ 'chrome 154' ]. The npm ci documentation explains why it succeeds where npm install does not: when a node_modules folder is already present, npm ci removes it automatically before it starts installing, so every package is extracted again from scratch.

npm ci also never writes to package.json or package-lock.json, so the fix leaves no trace in your diff. In the reproduction run that deleted node_modules first and then ran npm ci, package.json was byte-identical afterwards.

2. No lockfile? Delete node_modules and install#

npm ci refuses to run without package-lock.json. In that case remove the folder yourself, then install:

bash
rm -rf node_modules
npm install

On Windows PowerShell, the first line is Remove-Item -Recurse -Force node_modules.

3. If it comes back: check the npm cache#

The maintainer's reply above also mentions the npm cache. If a fresh install recreates the same incomplete folder, check the cache before reinstalling again:

bash
npm cache verify
npm ci

The npm cache documentation describes verify as checking the cache folder, garbage-collecting unneeded data and verifying the integrity of the cache index and all cached data. This step was not part of the reproduction above, where the cache was healthy.

Verify the fix#

Load browserslist directly from the project root. A healthy tree prints a browser list:

bash
node -e "console.log(require('browserslist')('last 1 Chrome version'))"
text
[ 'chrome 154' ]

You can also check that the file the error names now exists:

bash
ls node_modules/caniuse-lite/dist/unpacker/agents.js

Then run the command that failed (npm start, next dev, npm run build). If npm ls caniuse-lite shows several copies, run the node -e check from the folder of the package named in your require stack. Each copy can be broken on its own.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

When npm i caniuse-lite seems to work#

The most-voted Stack Overflow answer, with 65 votes, is npm i caniuse-lite. The reproduction shows when that is true. With a lockfile that held the older 1.0.30001813 as a transitive dependency, deleting its dist and running npm i caniuse-lite printed:

text
changed 1 package in 2s

npm moved to 1.0.30001815, extracted a fresh folder, and the error disappeared. The command worked because the version changed, not because of anything specific to caniuse-lite. When the broken copy is already the latest release, the same command prints up to date and repairs nothing.

The third answer pins an old release, npm i caniuse-lite@1.0.30001281. In the reproduction that also cleared the error, but only indirectly. npm installed the old version at the top level and gave browserslist its own fresh copy of 1.0.30001815 in node_modules/browserslist/node_modules. The project keeps a pinned dataset published on 17 November 2021, according to the npm registry, that nothing in it asked for. The second answer, npm update @babel/preset-env, was not reproduced here. Like the first, it can only help if it causes npm to replace the caniuse-lite folder.

None of these is needed when npm ci restores the tree as the lockfile describes it.

The next error#

Switching to npm ci can surface a different failure. If package-lock.json was produced with legacy-peer-deps and no longer matches package.json under your npm settings, npm ci stops with a list of Missing: … from lock file lines. That case is covered step by step in Fix Firebase Functions Deploy: Missing: X from lock file.

Copying a node_modules folder between machines is a related trap. Rollup's native binaries follow the operating system that ran the install, and the same "delete it and run npm ci where it runs" rule applies to Cannot find module @rollup/rollup-win32-x64-msvc. If the "Cannot find module" error instead comes from TypeScript in vite.config.ts (TS2307) rather than from Node at runtime, it is a TypeScript-side problem (a missing package, a stale TS server or the moduleResolution setting), not a half-installed folder. See Cannot find module '@vitejs/plugin-react'.

The caniuse-lite error is a reminder that a dependency folder can exist without being complete, and that npm install and npm ls did not notice the missing files in the reproduction. When a module path inside an installed package goes missing, reinstall the tree from the lockfile with npm ci before reaching for a new dependency.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote