Skip to content

[BUG] npm ci after npm install fails for file-based dependencies #9433

@mind-bending-forks

Description

@mind-bending-forks

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

We have started encountering a situation where running npm ci after npm install fails. This is preventing our build pipelines from running.

This is similar to other issues reported in the past couple of weeks (#9358, #9231), so perhaps has the same root cause. I have created a script that reproduces the problem using local file dependencies, and have determined that the regression occurs between npm 11.14.1 and 11.15.0.

I have tried tricks suggested in similar reported issues, such as running npm install twice, or running npm install --package-lock-only after npm install, but these do not work.

Expected Behavior

Running npm ci after npm install works without error.

Steps To Reproduce

Here is a script for a Linux environment with bash and npm available, e.g. Ubuntu 24.04.

#!/bin/bash

# enable exit on error
set -e

delete_packages() {
  rm -rf a b c
}

create_packages() {
  # create package a
  mkdir a
  pushd a > /dev/null
  cat <<EOF> package.json
{
  "name": "a",
  "version": "1.0.0",
  "private": true
}
EOF
  npm install --loglevel silent
  popd > /dev/null

  # create package b that depends on package a
  mkdir b
  pushd b > /dev/null
  mkdir lib
  ln -s ../../a lib/a
  cat <<EOF> package.json
{
  "name": "b",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "a": "file:lib/a"
  }
}
EOF
  npm install --loglevel silent
  popd > /dev/null

  # create package c that depends on packages a and b
  mkdir c
  pushd c > /dev/null
  mkdir lib
  ln -s ../../a lib/a
  ln -s ../../b lib/b
  cat <<EOF> package.json
{
  "name": "c",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "a": "file:lib/a",
    "b": "file:lib/b"
  }
}
EOF
  npm install --loglevel silent
  popd > /dev/null
}

# Setup

# Delete packages from any previous runs
delete_packages
# (Re)-create the packages
create_packages

# disable exit on error
set +e

pushd c > /dev/null
npm ci --loglevel warn
success="$?"
if [ $success -ne 0 ]; then
  echo "ERROR: Calling npm ci after npm install on package c fails" 2>&1
else
  echo "SUCCESS: Calling npm ci after npm install on package c succeeds"
fi
echo "Contents of c/package-lock.json are"
cat "package-lock.json"
popd > /dev/null
exit $success

Save it as run.bsh and make it executable. Running it will create three packages a, b (depends on a) and c (depends on a and b), in directories with the same name, and run npm install on all of them.

It will then run npm ci on package c.

Running this with npm 11.14.1 like so

sudo npm install --location=global npm@11.14.1
./run.bsh

gives

SUCCESS: Calling npm ci after npm install on package c succeeds
Contents of c/package-lock.json are
{
  "name": "c",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "c",
      "version": "1.0.0",
      "dependencies": {
        "a": "file:lib/a",
        "b": "file:lib/b"
      }
    },
    "lib/a": {
      "version": "1.0.0"
    },
    "lib/b": {
      "version": "1.0.0",
      "dependencies": {
        "a": "file:lib/a"
      }
    },
    "lib/b/lib/a": {
      "version": "1.0.0",
      "extraneous": true
    },
    "node_modules/a": {
      "resolved": "lib/a",
      "link": true
    },
    "node_modules/b": {
      "resolved": "lib/b",
      "link": true
    }
  }
}

whereas, calling this on npm 11.15.0 (or later, up to and including 11.16.0), like so

sudo npm install --location=global npm@11.15.0
./run.bsh

gives

npm error code EUSAGE
npm error
npm error `npm ci` can only install packages when your package.json and package-lock.json or npm-shrinkwrap.json are in sync. Please update your lock file with `npm install` before continuing.
npm error
npm error Missing: a@1.0.0 from lock file
npm error
npm error Clean install a project
npm error
npm error Usage:
npm error npm ci
npm error
npm error Options:
npm error [--install-strategy <hoisted|nested|shallow|linked>] [--legacy-bundling]
npm error [--global-style] [--omit <dev|optional|peer> [--omit <dev|optional|peer> ...]]
npm error [--include <prod|dev|optional|peer> [--include <prod|dev|optional|peer> ...]]
npm error [--strict-peer-deps] [--foreground-scripts] [--ignore-scripts]
npm error [--allow-directory <all|none|root>] [--allow-file <all|none|root>]
npm error [--allow-git <all|none|root>] [--allow-remote <all|none|root>] [--no-audit]
npm error [--no-bin-links] [--no-fund] [--dry-run]
npm error [-w|--workspace <workspace-name> [-w|--workspace <workspace-name> ...]]
npm error [--workspaces] [--include-workspace-root] [--install-links]
npm error
npm error   --install-strategy
npm error     Sets the strategy for installing packages in node_modules.
npm error
npm error   --legacy-bundling
npm error     Instead of hoisting package installs in `node_modules`, install packages
npm error
npm error   --global-style
npm error     Only install direct dependencies in the top level `node_modules`,
npm error
npm error   --omit
npm error     Dependency types to omit from the installation tree on disk.
npm error
npm error   --include
npm error     Option that allows for defining which types of dependencies to install.
npm error
npm error   --strict-peer-deps
npm error     If set to `true`, and `--legacy-peer-deps` is not set, then _any_
npm error
npm error   --foreground-scripts
npm error     Run all build scripts (ie, `preinstall`, `install`, and
npm error
npm error   --ignore-scripts
npm error     If true, npm does not run scripts specified in package.json files.
npm error
npm error   --allow-directory
npm error     Limits the ability for npm to install dependencies from directories.
npm error
npm error   --allow-file
npm error     Limits the ability for npm to install dependencies from tarball files.
npm error
npm error   --allow-git
npm error     Limits the ability for npm to fetch dependencies from git references.
npm error
npm error   --allow-remote
npm error     Limits the ability for npm to fetch dependencies from urls.
npm error
npm error   --audit
npm error     When "true" submit audit reports alongside the current npm command to the
npm error
npm error   --bin-links
npm error     Tells npm to create symlinks (or `.cmd` shims on Windows) for package
npm error
npm error   --fund
npm error     When "true" displays the message at the end of each `npm install`
npm error
npm error   --dry-run
npm error     Indicates that you don't want npm to make any changes and that it should
npm error
npm error   -w|--workspace
npm error     Enable running a command in the context of the configured workspaces of the
npm error
npm error   --workspaces
npm error     Set to true to run the command in the context of **all** configured
npm error
npm error   --include-workspace-root
npm error     Include the workspace root when workspaces are enabled for a command.
npm error
npm error   --install-links
npm error     When set file: protocol dependencies will be packed and installed as
npm error
npm error
npm error aliases: clean-install, ic, install-clean, isntall-clean
npm error
npm error Run "npm help ci" for more info
npm error A complete log of this run can be found in: /home/***/.npm/_logs/2026-05-29T11_23_50_044Z-debug-0.log
ERROR: Calling npm ci after npm install on package c fails
Contents of c/package-lock.json are
{
  "name": "c",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "c",
      "version": "1.0.0",
      "dependencies": {
        "a": "file:lib/a",
        "b": "file:lib/b"
      }
    },
    "lib/a": {
      "version": "1.0.0"
    },
    "lib/b": {
      "version": "1.0.0",
      "dependencies": {
        "a": "file:lib/a"
      }
    },
    "node_modules/a": {
      "resolved": "lib/a",
      "link": true
    },
    "node_modules/b": {
      "resolved": "lib/b",
      "link": true
    }
  }
}

Diffing the two package package-lock.json files, shows that the required block

    "lib/b/lib/a": {
      "version": "1.0.0",
      "extraneous": true
    },

is missing from package-lock.json since 11.15.0.

Environment

  • npm: 11.15.0 ... 11.16.0
  • Node.js: 24.16.0
  • OS Name: Ubuntu 22.04 / Ubuntu 24.04
  • System Model Name: VM
  • npm config:
; node bin location = /usr/local/bin/node
; node version = v24.16.0
; npm local prefix = /home/***/npm-local-file-dependency-bug
; npm version = 11.16.0
; cwd = /home/***/npm-local-file-dependency-bug
; HOME = /home/***
; Run `npm config ls -l` to show all defaults.

(I've replaced the home directory name by ***)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Bugthing that needs fixingNeeds Triageneeds review for next steps

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions