npm / npm/cli

[BUG] ERESOLVE when redoing npm install after replacing normal package with local tgz (peerDependency)

Open
#9,111 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Bug Priority 2
Dominant language
JavaScript
Stars
10.1k
Forks
4.7k
Avg merge
2d 2h
Merged PRs (30d)
19

Description

Is there an existing issue for this?
  • I have searched the existing issues
This issue exists in the latest npm version
  • I am using the latest npm
Current Behavior

Maybe be similar to https://github.com/npm/cli/issues/8647

After editing the package.json of my project, replacing a dependency foo: "^X.Y" by foo: "file:path/to/tgz" and rerun npm i, I get ERESOLVE

Workarounds include:

  • using --force
  • using --legacy-peer-deps
  • rm -rf node_modules package-lock.json
  • add overrides and manually specify versions for the actual dependencies that trigger the problem
Expected Behavior

After editing the package.json of my project, replacing a dependency foo: "^X.Y" by foo: "file:path/to/tgz" and rerun npm i, I expect npm to just reresolve the needed parts and produce a new package-lock.json/node_modules

Steps To Reproduce

reproduce.sh
Here's a bash script that uses well known packages deck.gl and luma.gl to reproduce the issue in a local project:
(note that the workaround with rm -rf node_modules package-lock.json looses all pinned versions, ie forces a global upgrade so is very different from the others)

31 error code ERESOLVE
32 error ERESOLVE could not resolve
33 error
34 error While resolving: project-c@1.0.0
34 error Found: @deck.gl/extensions@9.0.41
34 error node_modules/@deck.gl/extensions
34 error   @deck.gl/extensions@"file:/home/MYUSER/Downloads/ii/tarballs/deck.gl-extensions-9.2.99.tgz" from the root project
34 error
34 error Could not resolve dependency:
34 error @deck.gl/extensions@"file:/home/MYUSER/Downloads/ii/tarballs/deck.gl-extensions-9.2.99.tgz" from the root project
34 error
34 error Conflicting peer dependency: @luma.gl/core@9.2.6
34 error node_modules/@luma.gl/core
34 error   peer @luma.gl/core@"~9.2.0" from @deck.gl/extensions@9.2.99
34 error   node_modules/@deck.gl/extensions
34 error     @deck.gl/extensions@"file:/home/harperjon/Downloads/ii/tarballs/deck.gl-extensions-9.2.99.tgz" from the root project
34 error
34 error Fix the upstream dependency conflict, or retry
34 error this command with --force or --legacy-peer-deps
34 error to accept an incorrect (and potentially broken) dependency resolution.
35 error
35 error
35 error For a full report see:
35 error /home/harperjon/.npm/_logs/2026-03-13T07_27_22_443Z-eresolve-report.txt


━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
SUMMARY
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
  FAIL  npm install (no workaround)
  OK    overrides { @luma.gl/core: ~9.2.0 }
  OK    --legacy-peer-deps
  OK    --force
  FAIL  rm package-lock.json
  FAIL  rm node_modules (keep lockfile)
  OK    rm lockfile + node_modules (clean slate)
========================================
npm version: 11.6.2
node version: v24.13.0
========================================

▶ Phase 1: Install @deck.gl/core@9.0.41 + @deck.gl/extensions@9.0.41 from registry

added 26 packages, and audited 27 packages in 4s

found 0 vulnerabilities
  ✅ Registry install succeeded

▶ Phase 2: Create workspace with bumped versions (9.2.99)

added 12 packages, and audited 15 packages in 770ms

found 0 vulnerabilities
deck.gl-core-9.2.99.tgz
deck.gl-extensions-9.2.99.tgz
  ✅ Packed: deck.gl-core-9.2.99.tgz
deck.gl-extensions-9.2.99.tgz

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 0: Baseline — npm install (expect ERESOLVE)
npm error
npm error
npm error For a full report see:
npm error /home/MYUSER/.npm/_logs/2026-03-12T19_47_05_515Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/MYUSER/.npm/_logs/2026-03-12T19_47_05_515Z-debug-0.log

  💥 FAILED — npm install (no workaround)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 1: overrides in package.json

removed 14 packages, changed 5 packages, and audited 13 packages in 664ms

found 0 vulnerabilities

  ✅ OK     — overrides { @luma.gl/core: ~9.2.0 }

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 2: --legacy-peer-deps

removed 16 packages, changed 4 packages, and audited 11 packages in 802ms

found 0 vulnerabilities

  ✅ OK     — --legacy-peer-deps

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 3: --force
npm warn using --force Recommended protections disabled.

removed 14 packages, changed 5 packages, and audited 13 packages in 516ms

found 0 vulnerabilities

  ✅ OK     — --force

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 4: remove package-lock.json (keep node_modules)
npm error
npm error
npm error For a full report see:
npm error /home/MYUSER/.npm/_logs/2026-03-12T19_47_08_041Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/MYUSER/.npm/_logs/2026-03-12T19_47_08_041Z-debug-0.log

  💥 FAILED — rm package-lock.json

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 5: remove node_modules (keep package-lock.json)
npm error
npm error
npm error For a full report see:
npm error /home/MYUSER/.npm/_logs/2026-03-12T19_47_08_313Z-eresolve-report.txt
npm error A complete log of this run can be found in: /home/MYUSER/.npm/_logs/2026-03-12T19_47_08_313Z-debug-0.log

  💥 FAILED — rm node_modules (keep lockfile)

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Test 6: remove both package-lock.json AND node_modules

added 12 packages, and audited 13 packages in 612ms

found 0 vulnerabilities

  ✅ OK     — rm lockfile + node_modules (clean slate)
#!/usr/bin/env bash
#
# Minimal ERESOLVE repro + workaround tests
# Uses only standard @deck.gl / @luma.gl packages (~26 packages)
#
# Bug pattern:
#   Phase 1: Install from npm REGISTRY → lockfile locks @luma.gl/core@9.0.28
#   Phase 2: Switch to local TGZ (bumped peerDep ~9.2.0) → ERESOLVE
#
# Workarounds tested:
#   1) overrides in package.json
#   2) --legacy-peer-deps
#   3) --force
#   4) remove package-lock.json
#   5) remove node_modules only (does it help?)
#
set -euo pipefail

ROOT="$(cd "$(dirname "$0")" && pwd)"
TARBALLS="$ROOT/tarballs"
WORKSPACE="$ROOT/workspace"
PROJECTC="$ROOT/project-c"
BACKUP="$ROOT/.backup"

RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m'

echo "========================================"
echo "npm version: $(npm --version)"
echo "node version: $(node --version)"
echo "========================================"

rm -rf "$TARBALLS" "$WORKSPACE" "$PROJECTC" "$BACKUP"
mkdir -p "$TARBALLS" "$WORKSPACE/packages/core" "$WORKSPACE/packages/extensions" "$PROJECTC"

###########################################################
# Phase 1: Install from npm REGISTRY (old 9.0.x versions)
###########################################################

echo ""
echo -e "${BOLD}▶ Phase 1: Install @deck.gl/core@9.0.41 + @deck.gl/extensions@9.0.41 from registry${NC}"

cat > "$PROJECTC/package.json" <<'EOF'
{
  "name": "project-c",
  "version": "1.0.0",
  "dependencies": {
    "@deck.gl/core": "9.0.41",
    "@deck.gl/extensions": "9.0.41"
  }
}
EOF

(cd "$PROJECTC" && npm install)
echo -e "  ${GREEN}✅ Registry install succeeded${NC}"

# Save the registry-based state for reuse by each workaround
mkdir -p "$BACKUP"
cp "$PROJECTC/package-lock.json" "$BACKUP/package-lock.json"
cp -a "$PROJECTC/node_modules" "$BACKUP/node_modules"

###########################################################
# Phase 2: Create TGZ files for new versions (9.2.99)
###########################################################

echo ""
echo -e "${BOLD}▶ Phase 2: Create workspace with bumped versions (9.2.99)${NC}"

cat > "$WORKSPACE/package.json" <<'EOF'
{
  "name": "deck-gl-workspace",
  "version": "1.0.0",
  "private": true,
  "workspaces": ["packages/*"]
}
EOF

cat > "$WORKSPACE/packages/core/package.json" <<'EOF'
{
  "name": "@deck.gl/core",
  "version": "9.2.99",
  "dependencies": {
    "@luma.gl/core": "~9.2.0",
    "@luma.gl/engine": "~9.2.0"
  }
}
EOF

cat > "$WORKSPACE/packages/extensions/package.json" <<'EOF'
{
  "name": "@deck.gl/extensions",
  "version": "9.2.99",
  "peerDependencies": {
    "@deck.gl/core": "~9.2.0",
    "@luma.gl/core": "~9.2.0",
    "@luma.gl/engine": "~9.2.0"
  }
}
EOF

(cd "$WORKSPACE" && npm install)
(cd "$WORKSPACE" && npm pack --workspaces --pack-destination "$TARBALLS" --quiet)
echo -e "  ${GREEN}✅ Packed:${NC} $(ls "$TARBALLS"/*.tgz | xargs -I{} basename {})"

###########################################################
# Helper: write the tgz-based package.json
###########################################################

write_tgz_packagejson() {
  cat > "$PROJECTC/package.json" <<EOF
{
  "name": "project-c",
  "version": "1.0.0",
  "dependencies": {
    "@deck.gl/core": "file:$TARBALLS/deck.gl-core-9.2.99.tgz",
    "@deck.gl/extensions": "file:$TARBALLS/deck.gl-extensions-9.2.99.tgz"
  }
}
EOF
}

write_tgz_packagejson_with_overrides() {
  cat > "$PROJECTC/package.json" <<EOF
{
  "name": "project-c",
  "version": "1.0.0",
  "dependencies": {
    "@deck.gl/core": "file:$TARBALLS/deck.gl-core-9.2.99.tgz",
    "@deck.gl/extensions": "file:$TARBALLS/deck.gl-extensions-9.2.99.tgz"
  },
  "overrides": {
    "@luma.gl/core": "~9.2.0",
    "@luma.gl/engine": "~9.2.0"
  }
}
EOF
}

# Restore the registry-installed state (lockfile + node_modules)
restore_broken_state() {
  rm -rf "$PROJECTC/node_modules" "$PROJECTC/package-lock.json"
  cp "$BACKUP/package-lock.json" "$PROJECTC/package-lock.json"
  cp -a "$BACKUP/node_modules" "$PROJECTC/node_modules"
}

# Run npm install and report result
try_install() {
  local label="$1"
  shift
  set +e
  (cd "$PROJECTC" && npm install "$@" 2>&1) | tail -5
  local exit_code=${PIPESTATUS[0]}
  set -e
  echo ""
  if [ $exit_code -ne 0 ]; then
    echo -e "  ${RED}💥 FAILED${NC} — $label"
  else
    echo -e "  ${GREEN}✅ OK${NC}     — $label"
  fi
  RESULTS+=("$([ $exit_code -ne 0 ] && echo "FAIL" || echo "OK  ")|$label")
}

###########################################################
# Tests
###########################################################

RESULTS=()

# ── Test 0: Reproduce the bug ────────────────────────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 0: Baseline — npm install (expect ERESOLVE)${NC}"
restore_broken_state
write_tgz_packagejson
try_install "npm install (no workaround)"

# ── Test 1: overrides ────────────────────────────────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 1: overrides in package.json${NC}"
restore_broken_state
write_tgz_packagejson_with_overrides
try_install "overrides { @luma.gl/core: ~9.2.0 }"

# ── Test 2: --legacy-peer-deps ───────────────────────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 2: --legacy-peer-deps${NC}"
restore_broken_state
write_tgz_packagejson
try_install "--legacy-peer-deps" --legacy-peer-deps

# ── Test 3: --force ──────────────────────────────────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 3: --force${NC}"
restore_broken_state
write_tgz_packagejson
try_install "--force" --force

# ── Test 4: remove package-lock.json ─────────────────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 4: remove package-lock.json (keep node_modules)${NC}"
restore_broken_state
write_tgz_packagejson
rm "$PROJECTC/package-lock.json"
try_install "rm package-lock.json"

# ── Test 5: remove node_modules only ─────────────────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 5: remove node_modules (keep package-lock.json)${NC}"
restore_broken_state
write_tgz_packagejson
rm -rf "$PROJECTC/node_modules"
try_install "rm node_modules (keep lockfile)"

# ── Test 6: remove both lockfile + node_modules ──────────
echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}Test 6: remove both package-lock.json AND node_modules${NC}"
restore_broken_state
write_tgz_packagejson
rm -rf "$PROJECTC/node_modules" "$PROJECTC/package-lock.json"
try_install "rm lockfile + node_modules (clean slate)"

###########################################################
# Summary
###########################################################

echo ""
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${BOLD}SUMMARY${NC}"
echo -e "${BOLD}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
for r in "${RESULTS[@]}"; do
  status="${r%%|*}"
  label="${r#*|}"
  if [[ "$status" == "OK  " ]]; then
    echo -e "  ${GREEN}${status}${NC}  ${label}"
  else
    echo -e "  ${RED}${status}${NC}  ${label}"
  fi
done
echo ""

# Cleanup backup
rm -rf "$BACKUP"
Environment
  • npm: tested 11.9.0 and 11.11.0
  • Node.js: 24.14.0 or 25.8.1
  • OS Name: ubuntu
  • System Model Name:
  • npm config:

$ npm config ls -l
; "default" config from default values

_auth = (protected)
access = null
all = false
allow-same-version = false
also = null
audit = true
audit-level = null
auth-type = "web"
before = null
bin-links = true
browser = null
ca = null
cache = "/home/MYUSER/.npm"
cache-max = null
cache-min = 0
cafile = null
call = ""
cert = null
cidr = null
color = true
commit-hooks = true
cpu = null
depth = null
description = true
dev = false
diff = []
diff-dst-prefix = "b/"
diff-ignore-all-space = false
diff-name-only = false
diff-no-prefix = false
diff-src-prefix = "a/"
diff-text = false
diff-unified = 3
dry-run = false
editor = "vim"
engine-strict = false
expect-result-count = null
expect-results = null
fetch-retries = 2
fetch-retry-factor = 10
fetch-retry-maxtimeout = 60000
fetch-retry-mintimeout = 10000
fetch-timeout = 300000
force = false
foreground-scripts = false
format-package-lock = true
fund = true
git = "git"
git-tag-version = true
global = false
global-style = false
globalconfig = "/home/MYUSER/.nvm/versions/node/v24.13.0/etc/npmrc"
heading = "npm"
https-proxy = null
if-present = false
ignore-scripts = false
include = []
include-staged = false
include-workspace-root = false
init-author-email = ""
init-author-name = ""
init-author-url = ""
init-license = "ISC"
init-module = "/home/MYUSER/.npm-init.js"
init-private = false
init-type = "commonjs"
init-version = "1.0.0"
init.author.email = ""
init.author.name = ""
init.author.url = ""
init.license = "ISC"
init.module = "/home/MYUSER/.npm-init.js"
init.version = "1.0.0"
install-links = false
install-strategy = "hoisted"
json = false
key = null
legacy-bundling = false
legacy-peer-deps = false
libc = null
link = false
local-address = null
location = "user"
lockfile-version = null
loglevel = "notice"
logs-dir = null
logs-max = 10
; long = false ; overridden by cli
maxsockets = 15
message = "%s"
node-gyp = "/home/MYUSER/.nvm/versions/node/v24.13.0/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js"
node-options = null
noproxy = [""]
npm-version = "11.6.2"
offline = false
omit = []
omit-lockfile-registry-resolved = false
only = null
optional = null
os = null
otp = null
pack-destination = "."
package = []
package-lock = true
package-lock-only = false
parseable = false
prefer-dedupe = false
prefer-offline = false
prefer-online = false
prefix = "/home/MYUSER/.nvm/versions/node/v24.13.0"
preid = ""
production = null
progress = true
provenance = false
provenance-file = null
proxy = null
read-only = false
rebuild-bundle = true
registry = "https://registry.npmjs.org/"
replace-registry-host = "npmjs"
save = true
save-bundle = false
save-dev = false
save-exact = false
save-optional = false
save-peer = false
save-prefix = "^"
save-prod = false
sbom-format = null
sbom-type = "library"
scope = ""
script-shell = null
searchexclude = ""
searchlimit = 20
searchopts = ""
searchstaleness = 900
shell = "/bin/bash"
shrinkwrap = true
sign-git-commit = false
sign-git-tag = false
strict-peer-deps = false
strict-ssl = true
tag = "latest"
tag-version-prefix = "v"
timing = false
umask = 0
unicode = true
update-notifier = true
usage = false
user-agent = "npm/{npm-version} node/{node-version} {platform} {arch} workspaces/{workspaces} {ci}"
userconfig = "/home/MYUSER/.npmrc"
version = false
versions = false
viewer = "man"
which = null
workspace = []
workspaces = null
workspaces-update = true
yes = null

; "user" config from /home/MYUSER/.npmrc

//registry.npmjs.org/:_authToken = (protected)

; "cli" config from command line options

long = true

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the attached reproduce.sh script and inspect the generated package.json, package-lock.json, and node_modules state across its install phases. Trace npm install's dependency-resolution entry points for the transition from registry packages to local .tgz packages. Done means rerunning npm install after that change succeeds and updates the lockfile without requiring --force, --legacy-peer-deps, overrides, or deleting the existing state.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, nodejs
Domain
cli, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
42/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.