Cli: [BUG] Unable to resolve peer dependency if version contains ">="

Created on 4 Nov 2020  路  8Comments  路  Source: npm/cli

Current Behavior:

When resolving a peer dependency that has a ">=" in it's version, npm uses the latest version of that package to compare with the current dependency version in the package.json.

In this case: npm is looking for react 17, while react 16.13 is also a version that is suits >=16.9.0

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"^16.13.1" from the root project
npm ERR!   peer react@">=16.9.0" from @testing-library/[email protected]
npm ERR!   node_modules/@testing-library/react-hooks
npm ERR!     @testing-library/react-hooks@"3.4.1" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"17.0.1" from [email protected]
npm ERR! node_modules/react-test-renderer
npm ERR!   peer react-test-renderer@">=16.9.0" from @testing-library/[email protected]
npm ERR!   node_modules/@testing-library/react-hooks
npm ERR!     @testing-library/react-hooks@"3.4.1" from the root project
npm ERR! 

Expected Behavior:

npm should be able to resolve the [email protected] peer dependency from @testing-library/[email protected] because [email protected] is a dependency that matches react@>=16.9.0.

Steps To Reproduce:

  1. mkdir test-peers
  2. npm init
  3. npm install [email protected]
  4. npm install @testing-library/[email protected]

Environment:

  • OS: Mac OS 10.15.7
  • Node: 12.14.1
  • npm: 7.0.8
Bug Needs Triage Release 7.x

All 8 comments

I have to downgrade @testing-library/[email protected] because the peer react-test-renderer@">=16.9.0" will resolve in react-test-renderer@">=17.0.1". This version of react-test-renderer needs in turn react@"17.0.1"

@RobinWijnant you shouldn't need to do that; but you will need to manually specify react-test-renderer@16 as a dev dep.

Hmm.... yeah, so the react-test-renderer@">=16.9.0" peer dep resolves to [email protected], which requires react@17, and because @testing-library/react-hooks@3 requires react-test-renderer@>=16.9.0, it resolves to that higher version.

We do aggressively dedupe peerDeps, so if something _else_ were pulling in a lower version of react-test-renderer, we'd use that instead of 17, but what we don't do is roll back to an earlier version if it ends up bringing in a peer later down the line.

Eg:

a -> PEER(b@>=1)
b@1 -> PEER(c@>=1)
b@2 -> PEER(c@>=2)
c@1 -> PEER(d@>=1)
c@2 -> PEER(d@>=2)
thing -> (a, d@1) <-- this will cause troubles, because a->b@2->c@2->d@2 conflicts with d@1

The only way to resolve this would likely be to build up a full pubgrub style ruleset. We sort of approximate such a thing today, but rely on heuristics and nesting to get out of some of the stickiest situations.

This also highlights the problem with using >= rather than ^. We might be able to skirt around the worst hazards by preferring a >= match which is _also_ within the ^ range, where possible. In that case, the >=16.9.0 would resolve to the same as ^16.9.0, but be _able_ to dedupe against 17.0.1 if necessary.

Either of these ideas probably merit an RFC though.

Actually, just preferring a ^ match when >= is used won't do it. Too many packages out there have peer dependencies like webpack@^4.1.0 || ^5.0.3, and catching every possible iteration won't work out. Eventually, we're always going to have NP-hard territory to venture into.

I don't believe this should be closed. It currently breaks standard NPM7 installs of several major dependencies, such as for example styled-components:

npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: @[email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   dev react@"^16.8.0" from the root project
npm ERR!   peer react@">= 16.8.0" from [email protected]
npm ERR!   node_modules/styled-components
npm ERR!     dev styled-components@"^5.0.0" from the root project
npm ERR!     peer styled-components@">= 5" from [email protected]
npm ERR!     node_modules/jest-styled-components
npm ERR!       jest-styled-components@"^7.0.0" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"17.0.1" from [email protected]
npm ERR! node_modules/react-dom
npm ERR!   peer react-dom@">= 16.8.0" from [email protected]
npm ERR!   node_modules/styled-components
npm ERR!     dev styled-components@"^5.0.0" from the root project
npm ERR!     1 more (jest-styled-components)
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/csvanefalk/.npm/eresolve-report.txt for a full report.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/csvanefalk/.npm/_logs/2020-11-15T08_19_37_425Z-debug.log

I understand that the solution is complex (and I have nothing to contribute myself), but until one is in place it is probably useful to keep this (or a similar) issue open as a reference point for people running into it.

On that note, the above is temporarily resolvable by passing the --legacy-peer-deps flag.

Seems like you鈥檙e missing a top-level dependency on react-dom (that matches the same minor as react itself). If you fix that, what happens?

@ljharb yes, it works if I add explicit dependencies at the top level like in npm6, but my understanding was that npm7 resolves and installs peer dependencies in a way that meant this was no longer necessary, sorry if I got this wrong: https://github.com/npm/rfcs/blob/latest/implemented/0025-install-peer-deps.md

The problem seems to be that since the peer version of react-dom in this case is >= 16.8.0 (this is true for all my dependencies and sub-dependencies, none of them have a peer dependency on React 15 or 17), npm7 resolves the latest available version (17.0.1 in this case), but then concludes that it is not a match for the peer dependency.

It鈥檚 sometimes no longer necessary, but it鈥檚 still always better to be explicit.

Was this page helpful?
0 / 5 - 0 ratings