npm "EUNSUPPORTEDPROTOCOL" - Fix Unsupported Dependency URL Schemes
npm hit a dependency specifier whose protocol it does not support - link:, portal:, catalog:, patch: and similar are pnpm/Yarn-specific. npm cannot resolve the scheme and aborts with EUNSUPPORTEDPROTOCOL.
What this error means
npm install fails with code EUNSUPPORTEDPROTOCOL, naming a dependency whose version range uses a non-npm scheme. The repo usually works under the package manager that defines that protocol.
npm error code EUNSUPPORTEDPROTOCOL
npm error Unsupported URL Type "catalog:": catalog:
npm error at unsupportedURLType (...)Diagnose it: reproduce the CI install locally
Install failures are usually environment drift rather than a broken lockfile: a different package-manager major, a different Node version, or a cache that is being restored from a run with different inputs. Reproduce the CI conditions before changing the lockfile, because regenerating it hides the real cause.
# match the runner exactly, then install from a clean slate
node --version && npm --version
rm -rf node_modules
npm ci --foreground-scripts
# if that succeeds locally but fails in CI, the difference is the cache
# or the package-manager version, not your lockfileCommon causes
A dependency uses a manager-specific protocol
Schemes like catalog: (pnpm catalogs), portal:/link: (Yarn), or patch: are defined by pnpm/Yarn. npm has no resolver for them and rejects the spec.
Installing with the wrong tool
CI runs npm against a manifest authored for pnpm/Yarn. The protocols only make sense to the tool that owns the lockfile.
How to fix it
Install with the manager that defines the protocol
Use pnpm or Yarn (per the repo’s packageManager) so the protocol resolves natively.
corepack enable
pnpm install # for catalog: / pnpm-specific schemes
# or: yarn install # for portal:/link: under YarnRewrite to a spec npm understands
If you must use npm, replace the unsupported scheme with one npm supports - a version range, a file: path, or a git URL.
// pnpm/yarn (unsupported by npm)
"@app/lib": "link:../lib"
// npm-supported alternative
"@app/lib": "file:../lib"Verify the fix survives a cold cache
A green run immediately after a fix often proves nothing, because it restored a cache written before the change. Force a cold install once to confirm the fix is real.
# temporarily bust the cache key to prove the fix on a cold runner
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
# then bump this suffix once, run, and remove it
# key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}-v2How to prevent it
- Declare and pin the package manager via
packageManager+ Corepack. - Run CI with the manager that owns the lockfile and its protocols.
- Avoid manager-specific dependency schemes if the project must support npm.