The short answer: when you install a named version, such as
npm install react@^19.3.1, npm resolves a peer-dependency conflict with a warning ("ERESOLVE overriding peer dependency") and writes the result topackage.jsonand the lockfile. A fresh install of those same files has no override to fall back on, sonpm installandnpm cifail with ERESOLVE. That's why it works on your machine and fails on Vercel or CI. The fix is to make the versions agree: upgrade the package whose peer range is too narrow, or pin the one you upgraded.--legacy-peer-depsand--forceonly hide the conflict.
This happened on this site on 24 October 2026, during a routine Next.js security upgrade. The steps below come from that incident, reproduced afterwards from a clean copy of the repository.
A peer dependency is a package that a library expects you to install yourself, at a version inside a range the library declares. A 3D library built for React 19.2 declares React as a peer, with a range that says which React versions it has been tested with.
What happened
Next.js published security fixes on 14 October 2026, and React patched its own releases the same day. The upgrade looked like a one-liner:
npm install next@^16.4.3 react@^19.2.9 react-dom@^19.2.9
On a machine with an existing node_modules, it succeeded. It printed four warnings, which were easy to miss in a long install log:
npm warn ERESOLVE overriding peer dependency
npm warn peer react@"^18 || ~19.0.1 || ~19.1.2 || ^19.2.1" from @ai-sdk/react@4.0.12
npm warn peer react@">=19 <19.3" from @react-three/fiber@9.6.1
Because ^19.2.9 also matches 19.3.1, npm installed React 19.3.1 and saved "react": "^19.3.1". The build passed and every page generated. It was pushed.
Vercel's preview deployment failed about seven seconds after the build started, before compiling a line:
npm error code ERESOLVE
npm error ERESOLVE could not resolve
npm error peer react@">=19 <19.3" from @react-three/fiber@9.6.1
Error: Command "npm install" exited with 1
Why did it pass locally?
npm's documentation for the strict-peer-deps setting describes the default behaviour. Conflicting peer dependencies "will be resolved using the nearest non-peer dependency specification, even if doing so will result in some packages receiving a peer dependency outside the range". It adds: "When such an override is performed, a warning is printed."
So the local install did exactly what npm promises. It honoured the version that was asked for, overrode the 3D library's peer range, and warned. A fresh install from the committed files behaved differently:
| Scenario | Command | Result |
|---|---|---|
| Upgrade on a working machine | npm install react@^19.2.9 … | Passed with ERESOLVE overriding warnings |
| Vercel build | npm install (fresh) | Failed: ERESOLVE |
| Clean copy, npm 10.9.4 | npm install | Failed: ERESOLVE |
| Clean copy, npm 10.9.4 | npm ci | Failed: ERESOLVE |
| Clean copy, npm 12.2.1 | npm ci | Failed: ERESOLVE |
The lesson isn't that npm is inconsistent. The warning was the failure, delivered early and quietly.
Why didn't npm just upgrade the 3D library?
It could have. package.json asked for @react-three/fiber ^9.6.1, and version 9.8.0, published on 22 September 2026, widened its React peer range to >=19 <19.4. That covers React 19.3, which had been out since 9 September.
But the lockfile pinned fiber at 9.6.1, and npm doesn't move a locked package to a newer version to settle a peer conflict. The fix was available inside the allowed range. It just had to be asked for.
How to fix ERESOLVE properly
- Read the two ranges in the error. It names the package whose peer range you broke (
@react-three/fiber@9.6.1wants React<19.3) and the version you have (react@19.3.1). - Check for a newer version of the narrow package. Run
npm view @react-three/fiber@latest peerDependencies. If a newer release accepts your React, upgrade it in the same commit:npm install @react-three/fiber@^9.8.0. - Otherwise, pin the package you upgraded. This site pinned
reactandreact-domto~19.2.9, which carries the 14 October React security patch and stays inside fiber's range. It's the smaller change for a security-only pull request. Bump fiber and React together later, deliberately. - Reproduce CI before you push. Copy
package.jsonandpackage-lock.jsoninto an empty directory and runnpm ci --ignore-scripts. If that passes, Vercel's install will too. - Read the warnings. Treat
ERESOLVE overriding peer dependencyas a failure. Settingstrict-peer-deps=truein a project.npmrcmakes npm do that for you.
Why not --legacy-peer-deps?
Because it switches the check off rather than resolving it. npm's documentation says legacy-peer-deps causes npm "to completely ignore peerDependencies when building a package tree, as in npm versions 3 through 6". It also says use of the flag "is not recommended, as it will not enforce the peerDependencies contract that meta-dependencies may rely on."
Setting it on Vercel would have deployed a React version the 3D library had never declared support for. The build might have worked. The 3D floor-plan page might have broken in the browser, where no build log would show it. --force has the same problem with an even wider blast radius.
Common questions
Why does npm install work locally but fail on Vercel?
Because npm resolves peer-dependency conflicts with a warning when you install a named version, but a fresh install of the resulting package.json and lockfile has no such override and fails with ERESOLVE. Vercel installs fresh. Reproduce it locally with npm ci in an empty directory.
What does "npm warn ERESOLVE overriding peer dependency" mean?
npm installed a version outside a package's declared peer range because you asked for it explicitly, and printed a warning instead of failing. npm's documentation describes this as the default when strict-peer-deps is off. Treat it as a build that will fail somewhere else.
Should I use --legacy-peer-deps on Vercel?
Not as a fix. npm's documentation says the flag ignores peer dependencies entirely and is not recommended, because it doesn't enforce the peer contract packages rely on. It can deploy incompatible versions that fail at runtime instead of at install. Align the versions instead.
How do I test a dependency change before pushing?
Copy package.json and package-lock.json into an empty directory and run npm ci --ignore-scripts. That matches a clean CI install without running install scripts. If it fails with ERESOLVE, fix the versions locally before pushing.
The honest summary
Most "works on my machine" install failures are a warning that was printed and ignored. npm is consistent: it overrides with a warning when you ask for a version, and refuses when it has to work it out from your files. Read the ranges in the error, upgrade the narrow package if a newer one fits, and run a clean npm ci before pushing any dependency change.
If upgrades like this keep turning into incidents, that usually means the stack needs a maintenance routine rather than more heroics. That's part of what a web architecture consultant sets up. The wider upgrade picture is in upgrading from Next.js 15 to 16 and what changed in npm in 2026.
Sources: npm CLI config definitions: strict-peer-deps, legacy-peer-deps · @react-three/fiber on npm · Next.js security update, 14 October 2026
Written by Jagatjeet, a web architect and digital marketer based in Kamloops, BC. Jagatjeet (jagatjeet.com) builds and maintains Next.js sites for businesses and founders. Published 24 October 2026.