Skip to content
This repository has been archived by the owner on Aug 11, 2022. It is now read-only.

UNMET PEER DEPENDENCY #15708

Open
almadsen opened this issue Feb 8, 2017 · 22 comments
Open

UNMET PEER DEPENDENCY #15708

almadsen opened this issue Feb 8, 2017 · 22 comments
Labels

Comments

@almadsen
Copy link

almadsen commented Feb 8, 2017

Hi,
I'm opening this issue because npm is doing something I don't understand.

I get the error message UNMET PEER DEPENDENCY even though I have the said dependency installed.

I'm tying to install eslint-config-airbnb globally and it gives me:

npm install -g eslint-config-airbnb
/usr/local/lib
├── UNMET PEER DEPENDENCY eslint@^3.15.0
├─┬ eslint-config-airbnb@14.1.0
│ ├── UNMET PEER DEPENDENCY eslint@^3.15.0
│ └── UNMET PEER DEPENDENCY eslint-plugin-import@^2.2.0
├── UNMET PEER DEPENDENCY eslint-plugin-import@^2.2.0
├── UNMET PEER DEPENDENCY eslint-plugin-jsx-a11y@^3.0.2 || ^4.0.0
└── UNMET PEER DEPENDENCY eslint-plugin-react@^6.9.0

npm WARN eslint-config-airbnb@14.1.0 requires a peer of eslint@^3.15.0 but none was installed.
npm WARN eslint-config-airbnb@14.1.0 requires a peer of eslint-plugin-jsx-a11y@^3.0.2 || ^4.0.0 but none was installed.
npm WARN eslint-config-airbnb@14.1.0 requires a peer of eslint-plugin-import@^2.2.0 but none was installed.
npm WARN eslint-config-airbnb@14.1.0 requires a peer of eslint-plugin-react@^6.9.0 but none was installed.
npm WARN eslint-config-airbnb-base@11.1.0 requires a peer of eslint@^3.15.0 but none was installed.
npm WARN eslint-config-airbnb-base@11.1.0 requires a peer of eslint-plugin-import@^2.2.0 but none was installed.

I have the all installed, latest, and even tried to uninstall and the reinstall the exact required version, but still get the error.

And this is a quit common problem for me, getting UNMET PEER DEPENDENCY even though I have the said dependency installed.

npm v: 4.1.2
node v: 7.5.0
npm config get registry: https://registry.npmjs.org/
macOS 10.12.3

@alexduan
Copy link

I have been receiving similar notices as well with 7.5.0. Switching to an older version of node fixes the issue.

@GoodGuyNick
Copy link

I have same errors but with node v6.9.5

@hell0world
Copy link

hell0world commented Feb 12, 2017

same here~node v6.9.5

@marhalpert
Copy link

marhalpert commented Mar 7, 2017

same here~node v6.9.5

I am not installing it globally

@camloken
Copy link

Same issue here running node 7.2.0

@RandyRomero
Copy link

RandyRomero commented Jun 16, 2017

Same here on two different machines with eslint 4.0. Node v 8.1.0. And eslint doesn't work. Can't find anything related in Google.

npm ERR! peer dep missing: eslint@^3.19.0, required by eslint-config-airbnb@15.0.1
npm ERR! peer dep missing: eslint@2.x - 3.x, required by eslint-plugin-import@2.3.0
npm ERR! peer dep missing: eslint@^2.10.2 || 3.x, required by eslint-plugin-jsx-a11y@5.0.3
npm ERR! peer dep missing: eslint@^3.19.0, required by eslint-config-airbnb-base@11.2.0

On machine with eslint 3.20 everything is ok.

@ShaunEgan
Copy link

I have the same issue with esline@4.0.0, node v6.10.1

@iarna iarna added the bug label Jul 6, 2017
@iarna
Copy link
Contributor

iarna commented Jul 6, 2017

Hey, could you all give a try again with npm@5, we fixed a whole slew of issues and I think I fixed this one.

@TodayyadoT
Copy link

TodayyadoT commented Jul 31, 2017

same here~node v7.4.0

Anyone fixed it?

@daraclare
Copy link

@iarna Thanks for your suggestion, I updated to the latest version of npm 5.3.0, uninstalled both eslint and eslint-plugin-import and reinstalled them, and I no longer get the error. Thank you!

@jhermsmeier
Copy link

This still appears to be a problem with npm@5;

$ node -v
v8.7.0
$ npm -v
5.5.1
$ npm ls

# ... lines omitted for brevity ...

│   └─┬ yauzl@2.4.1
│     └── fd-slicer@1.0.1 deduped
├─┬ electron-builder@19.9.1
│ ├─┬ 7zip-bin@2.2.7
│ │ ├── UNMET OPTIONAL DEPENDENCY 7zip-bin-linux@^1.1.0
│ │ ├── 7zip-bin-mac@1.0.1
│ │ └── UNMET OPTIONAL DEPENDENCY 7zip-bin-win@^2.1.1
│ ├─┬ UNMET PEER DEPENDENCY ajv@5.2.5
│ │ ├── co@4.6.0
│ │ ├── fast-deep-equal@1.0.0
│ │ ├── json-schema-traverse@0.3.1
│ │ └── json-stable-stringify@1.0.1 deduped
│ ├── ajv-keywords@2.1.0
│ ├─┬ asar-integrity@0.1.1
│ │ ├── bluebird-lst@1.0.5 deduped
│ │ └── fs-extra-p@4.4.4 deduped

# ... lines omitted for brevity ...

npm ERR! peer dep missing: ajv@>=5.0.0, required by ajv-keywords@2.1.0

@JESii
Copy link

JESii commented Nov 3, 2017

This is the bane of my existence in node -- ruby has bundler and it just works!
node v8.8.0
npm v5.5.1
webpack v3.1.0

If I install the version that's requested, then another "UNMET PEER DEPENDENCY" shows up
npm ls
image

npm install webpack@2.7.0
package.json is updated to this version
but webpack version is still 3.1.0
so I say to myself -- maybe it's the global webpack that's causing the problem so I
npm uninstall -g webpack
BOOM!
image

The rabbit hole just got bigger!

@seila23
Copy link

seila23 commented Nov 30, 2017

here the solution :
npm install --save-dev eslint eslint-config-airbnb eslint-plugin-jsx-a11y eslint-plugin-import eslint-plugin-react

@dzf0023
Copy link

dzf0023 commented Jan 19, 2018

@seila23 could you please explain your solution more clearly....Thank you

@seila23
Copy link

seila23 commented Jan 26, 2018

just install 5 library :

  1. eslint
  2. eslint-config-airbnb
  3. eslint-plugin-jsx-a11y
  4. eslint-plugin-import
  5. eslint-plugin-react

@nswarte
Copy link

nswarte commented Feb 7, 2018

Hi,
I can reproduce the same issue with other dependencies w/ npm 5.6.0 and node 8.9.4.
The unexpected UNMET PEER DEPENDENCY disappears only if the installed packaged version exactly matches the version number in the comparator used for specifying the peer dependency.
For instance:
my package.json:

{
  "name": "peerdeptest",
  "version": "0.0.1",
  "description": "",
  "files": [
    "dist"
  ],
  "author": "nico",
  "license": "UNLICENSED",
  "devDependencies": {
    "typedoc": "0.6.0",
    "typedoc-webpack-plugin": "^1.1.4"
  }
}

and typedoc-webpack-plugin package.json specifies the typedoc peer dependency this way:

"peerDependencies": {
    "typedoc": ">= 0.5.0"
  }

So I'm getting the following errors when doing npm list:

+-- UNMET PEER DEPENDENCY typedoc@0.6.0
| +-- @types/fs-extra@2.1.0
| | `-- @types/node@9.4.1
| +-- @types/handlebars@4.0.36
...
npm ERR! peer dep missing: typedoc@^0.5.0, required by typedoc-webpack-plugin@1.1.4

Even so the peer dependency version is specified using >=0.5.0, a higher installed version (0.6.0) yield to UNMET error.
Now if I change my package.json to specify exactly 0.5.0 as the version to install for typedoc, errors are cleared:

+-- typedoc@0.5.0
| +-- fs-extra@0.30.0
| | +-- graceful-fs@4.1.11
| | +-- jsonfile@2.4.0
...

Hope this could help track down the problem.

@bjornstar
Copy link

I've created a very simple set of packages to reproduce this problem based on real world packages that exhibit this behavior:

https://www.npmjs.com/package/@peer-deps-repro/main

Steps to reproduce

git clone git@github.com:peer-deps-repro/main.git
cd main
npm install

The current major version has this incorrect behavior:

$> node -v
v8.9.4
$> npm -v
5.6.0
$> npm install
npm WARN @peer-deps-repro/dep-e@1.0.0 requires a peer of @peer-deps-repro/dep-d@6.0.0 but none is installed. You must install peer dependencies yourself.

added 6 packages in 1.796s
$> echo $?
0
$> npm ls
@peer-deps-repro/main@1.0.1 /mnt/f/main
├─┬ @peer-deps-repro/dep-a@1.0.0
│ └─┬ @peer-deps-repro/dep-c@1.0.0
│   └── @peer-deps-repro/dep-d@5.0.0
└─┬ @peer-deps-repro/dep-b@3.0.0
  ├── UNMET PEER DEPENDENCY @peer-deps-repro/dep-d@6.0.0
  └── @peer-deps-repro/dep-e@1.0.0

npm ERR! peer dep missing: @peer-deps-repro/dep-d@6.0.0, required by @peer-deps-repro/dep-e@1.0.0
$> echo $?
1
$>

Going back one major version, the install still behaves incorrectly:

$> node -v
v6.10.2
$> npm -v
4.5.0
$> npm install
@peer-deps-repro/main@1.0.1 /mnt/f/main
├─┬ @peer-deps-repro/dep-a@1.0.0
│ └─┬ @peer-deps-repro/dep-c@1.0.0
│   └── @peer-deps-repro/dep-d@5.0.0
└─┬ @peer-deps-repro/dep-b@3.0.0
  └── @peer-deps-repro/dep-e@1.0.0

npm WARN @peer-deps-repro/dep-e@1.0.0 requires a peer of @peer-deps-repro/dep-d@6.0.0 but none was installed.
$> echo $?
0
$> npm ls
@peer-deps-repro/main@1.0.1 /mnt/f/main
├─┬ @peer-deps-repro/dep-a@1.0.0
│ └─┬ @peer-deps-repro/dep-c@1.0.0
│   └── @peer-deps-repro/dep-d@5.0.0
└─┬ @peer-deps-repro/dep-b@3.0.0
  ├── UNMET PEER DEPENDENCY @peer-deps-repro/dep-d@6.0.0
  └── @peer-deps-repro/dep-e@1.0.0

npm ERR! peer dep missing: @peer-deps-repro/dep-d@6.0.0, required by @peer-deps-repro/dep-e@1.0.0
$> echo $?
1
$>

Going back 2 major versions it installs correctly:

$ node -v
v4.8.7
$> npm -v
2.15.11
$> rm -rf node_modules/
$> node -v
v4.8.7
$> npm -v
2.15.11
$> npm install
@peer-deps-repro/dep-b@3.0.0 node_modules/@peer-deps-repro/dep-b
├── @peer-deps-repro/dep-e@1.0.0
└── @peer-deps-repro/dep-d@6.0.0

@peer-deps-repro/dep-a@1.0.0 node_modules/@peer-deps-repro/dep-a
└── @peer-deps-repro/dep-c@1.0.0 (@peer-deps-repro/dep-d@5.0.0)
$> echo $?
0
$> npm ls
@peer-deps-repro/main@1.0.1 /mnt/f/main
├─┬ @peer-deps-repro/dep-a@1.0.0
│ └─┬ @peer-deps-repro/dep-c@1.0.0
│   └── @peer-deps-repro/dep-d@5.0.0
└─┬ @peer-deps-repro/dep-b@3.0.0
  ├── @peer-deps-repro/dep-d@6.0.0
  └── @peer-deps-repro/dep-e@1.0.0

$> echo $?
0
$>

@bjornstar
Copy link

Looking at the file structure, it actually does install correctly, npm just fails to enumerate them properly.

$> find node_modules/
node_modules/
node_modules/@peer-deps-repro
node_modules/@peer-deps-repro/dep-a
node_modules/@peer-deps-repro/dep-a/LICENSE
node_modules/@peer-deps-repro/dep-a/package.json
node_modules/@peer-deps-repro/dep-a/README.md
node_modules/@peer-deps-repro/dep-b
node_modules/@peer-deps-repro/dep-b/LICENSE
node_modules/@peer-deps-repro/dep-b/node_modules
node_modules/@peer-deps-repro/dep-b/node_modules/@peer-deps-repro
node_modules/@peer-deps-repro/dep-b/node_modules/@peer-deps-repro/dep-d
node_modules/@peer-deps-repro/dep-b/node_modules/@peer-deps-repro/dep-d/LICENSE
node_modules/@peer-deps-repro/dep-b/node_modules/@peer-deps-repro/dep-d/package.json
node_modules/@peer-deps-repro/dep-b/node_modules/@peer-deps-repro/dep-d/README.md
node_modules/@peer-deps-repro/dep-b/package.json
node_modules/@peer-deps-repro/dep-b/README.md
node_modules/@peer-deps-repro/dep-c
node_modules/@peer-deps-repro/dep-c/LICENSE
node_modules/@peer-deps-repro/dep-c/package.json
node_modules/@peer-deps-repro/dep-c/README.md
node_modules/@peer-deps-repro/dep-d
node_modules/@peer-deps-repro/dep-d/LICENSE
node_modules/@peer-deps-repro/dep-d/package.json
node_modules/@peer-deps-repro/dep-d/README.md
node_modules/@peer-deps-repro/dep-e
node_modules/@peer-deps-repro/dep-e/LICENSE
node_modules/@peer-deps-repro/dep-e/package.json
node_modules/@peer-deps-repro/dep-e/README.md
$>

Which would explain why apps still function even though npm is spitting out errors and warnings.

@filipesilva
Copy link

@bjornstar Yes I think #19877 is a duplicate of this one.

You said

Looking at the file structure, it actually does install correctly, npm just fails to enumerate them properly.

I don't think that it's installed correctly. I ran your repro steps and it resolves to a toplevel dep-d@5.0.0 alongside dep-e@1.0.0, thus failing the peer dependency.

dep-d@6.0.0 and only be found at inside node_modules/@peer-deps-repro/dep-b/node_modules/, from where dep-e was hoisted out.

Code might work but only because it works with the wrong peerdep regardless. This is still a real peer dependency problem.

When dep-e tries to require dep-d from node_modules, it will get dep-d@5.0.0 instead of dep-b/node_modules/dep-d@6.0.0.

Note: omitted @peer-deps-repro to make it clearer.

@bjornstar
Copy link

it resolves to a toplevel dep-d@5.0.0 alongside dep-e@1.0.0, thus failing the peer dependency.

That's not how node's require works.

dep-b requires dep-d@6.0.0 and dep-e@1.0.0. dep-e@1.0.0 has a peer dependency of dep-d@6.0.0

When dep-e requires dep-d within the context of dep-b it will get dep-d@6.0.0 from the dependencies of dep-b which is the correct behavior, but npm detects this incorrectly.

I've just released 2 new versions of the main repo with some instrumentation to make it more clear:

main@1.1.0

This version has an invalid peer dependency. dep-e@1.1.0 wants dep-d@6.1.0, but dep-b@3.1.0 has required dep-d@5.1.0 which is invalid. npm should fail to install this version with a big error saying invalid peer dependency, but it displays a warning and does not fail at all.

main@1.2.0

This version has all correct dependencies, but npm complains anyway.

The newly instrumented code logs the package name and version when it is required in node. Here's the output showing the correct behavior:

$> node .
@peer-deps-repro/main 1.2.0
@peer-deps-repro/dep-a 1.2.0
@peer-deps-repro/dep-b 3.2.0
@peer-deps-repro/dep-d 6.1.0
@peer-deps-repro/dep-e 1.1.0
@peer-deps-repro/dep-d 5.1.0
@peer-deps-repro/dep-c 1.1.0
$> 

There are multiple problems with the current peer dependency warnings, but the one I want to focus on is the spurious warnings when no problem exists. I think I have a fix for it, but working with this codebase is a bit more work than I anticipated.

diff --git a/lib/install/deps.js b/lib/install/deps.js
index 54cc525..075c9db 100644
--- a/lib/install/deps.js
+++ b/lib/install/deps.js
@@ -683,8 +683,10 @@ var validatePeerDeps = exports.validatePeerDeps = function (tree, onInvalid) {
     try {
       var spec = npa.resolve(pkgname, version)
     } catch (e) {}
-    var match = spec && findRequirement(tree.parent || tree, pkgname, spec)
-    if (!match) onInvalid(tree, pkgname, version)
+    tree.requiredBy.forEach(function (requiredBy) {
+      var match = spec && findRequirement(requiredBy, pkgname, spec)
+      if (!match) onInvalid(tree, pkgname, version)
+    })
   })
 }

This doesn't fix any of the other problems, but it does cause the validator to resolve the dependencies correctly. I'll raise a PR, but I've already spent way too much time making the repro steps to write the tests for it.

@filipesilva
Copy link

@bjornstar I really appreciate you taking the time to explain this to me, as I am not not fully familiar with the resolve internals.

I pulled your repro, updated to v1.2.0 and saw the same output. Below is the output of npm ls:

$ npm ls
@peer-deps-repro/main@1.2.0 D:\sandbox\main
+-- @peer-deps-repro/dep-a@1.2.0
| `-- @peer-deps-repro/dep-c@1.1.0
|   `-- @peer-deps-repro/dep-d@5.1.0
`-- @peer-deps-repro/dep-b@3.2.0
  +-- UNMET PEER DEPENDENCY @peer-deps-repro/dep-d@6.1.0
  `-- @peer-deps-repro/dep-e@1.1.0

npm ERR! peer dep missing: @peer-deps-repro/dep-d@6.1.0, required by @peer-deps-repro/dep-e@1.1.0

And here is my directory structure:

D:\sandbox\main
└── node_modules
|  └── @peer-deps-repro
|     ├── dep-a
|     ├── dep-b
|     |  └── node_modules
|     |  |  └── @peer-deps-repro
|     |  |     └── dep-d
|     ├── dep-c
|     ├── dep-d
|     └── dep-e

Then I went into main.js changed it to show only the dep-b logs:

var pkg = require('./package.json');
console.log(pkg.name, pkg.version);

// require('@peer-deps-repro/dep-a');
require('@peer-deps-repro/dep-b');

I went into node_modules/@peer-deps-reprio/dep-b/index.js and left only the dep-e logs:

var pkg = require('./package.json');
console.log(pkg.name, pkg.version);

// require('@peer-deps-repro/dep-d');
require('@peer-deps-repro/dep-e');

I believe this should print the versions that dep-e is using from within dep-b:

$ node .
@peer-deps-repro/main 1.2.0
@peer-deps-repro/dep-b 3.2.0
@peer-deps-repro/dep-e 1.1.0
@peer-deps-repro/dep-d 5.1.0

You said

When dep-e requires dep-d within the context of dep-b it will get dep-d@6.0.0 from the dependencies of dep-b which is the correct behavior, but npm detects this incorrectly.

But looking at these logs it seems like dep-e@1.1.0, which has a dep-d@6.1.0 peerdep, ends up getting dep-d@5.1.0 thus violating its peerdep. I don't think the that dep-e being imported from within dep-b made any difference, it still got the closest one (./node_modules/dep-d@5.1.0 instead of node_modules/dep-b/node_modules/dep-d@6.1.0).

Am I missing something in this reasoning? I don't mean to be difficult or anything, I just want to confirm we're looking at the same thing and taking the same conclusions.

@bjornstar
Copy link

Aw man, looks like you are right @filipesilva. I guess it was just wishful thinking that npm's peer dependencies implementation wasn't broken for the last 3 years. I was really hoping it was just a validation bug.

I've updated the instrumentation for this repro case to make it clear which module gets which dependency and it's as you said. Here's the output from main@1.3.1 using npm@5.6.0 to install:

$> nvm use 8
Now using node v8.9.4 (npm v5.6.0)
$> rm -rf node_modules && npm install && node .
npm WARN @peer-deps-repro/dep-e@1.2.0 requires a peer of @peer-deps-repro/dep-d@6.2.0 but none is installed. You must install peer dependencies yourself.

added 6 packages in 1.556s
{
  "pkgName": "@peer-deps-repro/main",
  "pkgVersion": "1.3.1",
  "depA": {
    "pkgName": "@peer-deps-repro/dep-a",
    "pkgVersion": "1.3.0",
    "depB": {
      "pkgName": "@peer-deps-repro/dep-b",
      "pkgVersion": "3.3.0",
      "depD": {
        "pkgName": "@peer-deps-repro/dep-d",
        "pkgVersion": "6.2.0"
      },
      "depE": {
        "pkgName": "@peer-deps-repro/dep-e",
        "pkgVersion": "1.2.0",
        "depD": {
          "pkgName": "@peer-deps-repro/dep-d",
          "pkgVersion": "5.2.0"
        }
      }
    },
    "depC": {
      "pkgName": "@peer-deps-repro/dep-c",
      "pkgVersion": "1.2.0",
      "depD": {
        "pkgName": "@peer-deps-repro/dep-d",
        "pkgVersion": "5.2.0"
      }
    }
  },
  "depB": {
    "pkgName": "@peer-deps-repro/dep-b",
    "pkgVersion": "3.3.0",
    "depD": {
      "pkgName": "@peer-deps-repro/dep-d",
      "pkgVersion": "6.2.0"
    },
    "depE": {
      "pkgName": "@peer-deps-repro/dep-e",
      "pkgVersion": "1.2.0",
      "depD": {
        "pkgName": "@peer-deps-repro/dep-d",
        "pkgVersion": "5.2.0"
      }
    }
  }
}
$>

and the same thing using npm@2.15.11

$> nvm use 4
Now using node v4.8.7 (npm v2.15.11)
$> rm -rf node_modules && npm install && node .
@peer-deps-repro/dep-b@3.3.0 node_modules/@peer-deps-repro/dep-b
├── @peer-deps-repro/dep-d@6.2.0
└── @peer-deps-repro/dep-e@1.2.0

@peer-deps-repro/dep-a@1.3.0 node_modules/@peer-deps-repro/dep-a
└── @peer-deps-repro/dep-c@1.2.0 (@peer-deps-repro/dep-d@5.2.0)
{
  "pkgName": "@peer-deps-repro/main",
  "pkgVersion": "1.3.1",
  "depA": {
    "pkgName": "@peer-deps-repro/dep-a",
    "pkgVersion": "1.3.0",
    "depB": {
      "pkgName": "@peer-deps-repro/dep-b",
      "pkgVersion": "3.3.0",
      "depD": {
        "pkgName": "@peer-deps-repro/dep-d",
        "pkgVersion": "6.2.0"
      },
      "depE": {
        "pkgName": "@peer-deps-repro/dep-e",
        "pkgVersion": "1.2.0",
        "depD": {
          "pkgName": "@peer-deps-repro/dep-d",
          "pkgVersion": "6.2.0"
        }
      }
    },
    "depC": {
      "pkgName": "@peer-deps-repro/dep-c",
      "pkgVersion": "1.2.0",
      "depD": {
        "pkgName": "@peer-deps-repro/dep-d",
        "pkgVersion": "5.2.0"
      }
    }
  },
  "depB": {
    "pkgName": "@peer-deps-repro/dep-b",
    "pkgVersion": "3.3.0",
    "depD": {
      "pkgName": "@peer-deps-repro/dep-d",
      "pkgVersion": "6.2.0"
    },
    "depE": {
      "pkgName": "@peer-deps-repro/dep-e",
      "pkgVersion": "1.2.0",
      "depD": {
        "pkgName": "@peer-deps-repro/dep-d",
        "pkgVersion": "6.2.0"
      }
    }
  }
}
$>

In all actuality, I think we should be able to remove peer dependencies since we are deduping now. I'll go ahead and close my PR as it doesn't fix anything.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests