Skip to content
Latchkey LogoLatchkey home

GitHub Actions Dependencies lock file is not found in setup-node

A GitHub Actions Dependencies lock file is not found error is actions/setup-node refusing to guess: with cache set and no cache-dependency-path, it reads the workspace root one level deep and looks for one of three exact filenames. The list of filenames it prints tells you which package manager it thought you were using, and that is often the real mistake.

How setup-node picks a lockfile to hash, and the two different errors a miss produces
Which branch setup-node takes depends on one input. The two branches fail with different text, and only one of them prints the filename list.

What this error means

The job fails inside Set up Node.js, before a single dependency is installed, and the step has already printed the Node version it resolved. The failure line names an absolute path, which is the checkout directory, and then a comma-separated list of filenames with no spaces between them. Nothing in the run is wrong except that the action could not find a file to hash for a cache key. If you have just moved the project into a monorepo, or just added cache: npm to a step that did not have it, this is the failure you get on the next push.

Actions log, quoted from JustAlexeyDev/EvaOS#19
Error: Dependencies lock file is not found in /home/runner/work/EvaOS/EvaOS. Supported file patterns: package-lock.json,npm-shrinkwrap.json,yarn.lock

A minimal workflow that produces it

This file is written for this page and has never been run. It is the smallest shape that produces the error: an application in packages/app, a cache input with nothing telling the action where to look, and a lockfile that is committed one directory below where the action searches. The checkout is present and correct, which is the point.

.github/workflows/ci.yml (illustrative)
name: ci
on:
  push:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm
      - run: npm ci
        working-directory: packages/app

Common causes

The lockfile is real but is not at the top of the checkout

The common one by a wide margin. A monorepo, a repository whose application lives under app/, or a workspace root holding only a package.json all fail this way. The action never descends, so a lockfile two directories down is invisible to it. The path in the message is the checkout root, and the file you are thinking of is not in it.

setup-node runs before actions/checkout

If the checkout has not happened, GITHUB_WORKSPACE exists and is empty, so the listing is empty and the search fails at once. Every example in the action's own documentation puts actions/checkout first. This is easy to create by accident when steps are reordered to speed a job up, because setup-node is fast and looks like it should go first.

The lockfile is not committed

A lockfile in .gitignore is not in the checkout, so it is not in the listing either. This is commoner than it sounds in repositories that were once libraries, because ignoring the lockfile is reasonable advice for a published package and the opposite of what a caching CI job needs. If git ls-files does not print it, the runner will not see it.

The cache value names a package manager you are not using

The three lists are not interchangeable, and one gap catches people repeatedly: cache: npm accepts a yarn.lock, but nothing except cache: pnpm accepts a pnpm-lock.yaml. A pnpm repository with cache: npm copied from a template fails every time, and the printed list is the tell, because it will not mention pnpm at all.

How to fix it

Read the filename list before you touch the path

  1. Take the comma-separated list from the message and compare it to the lockfile you actually have.
  2. If your lockfile is not in that list, the cache value names the wrong package manager, and the path is not the problem.
  3. If it is in the list, compare the path in the message to where the file really is.
  4. Confirm the file is committed with git ls-files before assuming the action is at fault.

Point cache-dependency-path at the file you have

The fix for every layout where the lockfile is not at the root, and the illustrative workflow above with one input added. The value is relative to the workspace, so it starts at the repository root regardless of any working-directory on a later step.

.github/workflows/ci.yml, corrected (illustrative)
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: npm
          cache-dependency-path: packages/app/package-lock.json
      - run: npm ci
        working-directory: packages/app

Use a glob or a list when there is more than one lockfile

The input takes a wildcard or a multiline list, and the advanced usage guide documents both. A glob keys the cache on every lockfile in the tree, so any dependency change invalidates it: right for a workspace installed from the root, wrong for independent packages that should each keep their own cache.

.github/workflows/ci.yml (illustrative)
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          cache: pnpm
          cache-dependency-path: |
            packages/app/pnpm-lock.yaml
            packages/api/pnpm-lock.yaml

If you do not want the cache, turn it off rather than working around it

Creating an empty lockfile at the root to satisfy the search is a fix that will produce a cache key nobody wants and a restore that never helps. If the job genuinely has nothing worth caching, drop the cache input, or set package-manager-cache to false, which the action has carried since version 5 and which disables the built-in caching without disabling the action.

.github/workflows/ci.yml (illustrative)
      - uses: actions/setup-node@v7
        with:
          node-version: 24
          package-manager-cache: false

The search is one directory deep and matches exact names

The function that raises this is findLockFile in the action source: twelve lines and six statements, of which the two below are the search and its guard. It reads the workspace directory, takes the package manager's list of lockfile names, and returns the first name in that listing. There is no recursion and no glob: the match is an exact string comparison against the entries at the top of the checkout.

That is why the message prints a path and a list. The path is GITHUB_WORKSPACE, so it says where the action looked, and the list is its own record of what it wanted. Which list you get depends on the value of cache, and the three do not overlap the way people assume.

actions/setup-node, src/cache-restore.ts
const lockFile = lockFiles.find(item => rootContent.includes(item));
if (!lockFile) {
  throw new Error(
    `Dependencies lock file is not found in ${workspace}. Supported file patterns: ${lockFiles.toString()}`
  );
}
cache valueFilenames it looks for, in orderWhere it looks
npmpackage-lock.json, npm-shrinkwrap.json, yarn.lockThe top level of the checkout, only
yarnyarn.lockThe top level of the checkout, only
pnpmpnpm-lock.yamlThe top level of the checkout, only

Setting cache-dependency-path changes which error you get

The branch above runs only when cache-dependency-path is empty. Set it, and the action skips findLockFile and hands your value straight to hashFiles, which is a glob. A glob that matches nothing has no filename list to print, so it raises different text instead: Some specified paths were not resolved, followed by an explanation that it cannot cache dependencies.

The two messages are a diagnostic, not a nuisance. The one with the filename list means the action was guessing and guessed an empty directory. The other means you said exactly where to look and it found nothing there, which is usually a typo, a path relative to the wrong root, or a lockfile in .gitignore.

The README states the default plainly: the action "defaults to search for the dependency file (package-lock.json, npm-shrinkwrap.json or yarn.lock) in the repository root", and points at cache-dependency-path "for cases when multiple dependency files are used, or they are located in different subdirectories". A monorepo is always the second case.

What you setWhat the action doesWhat a miss says
cache onlyReads the checkout root for known filenamesDependencies lock file is not found, with the list
cache and cache-dependency-pathGlobs your pattern and hashes the matchesSome specified paths were not resolved
NeitherNo cache, no lockfile lookup, no failureNothing, and every run downloads again

Why there is no recorded run on this page

The failure happens inside an action before any shell runs, so there is no runner state involved, nothing transient to retry, and nothing a managed runner could repair: the file is either at the path the action reads or it is not, on every attempt. So this page carries an illustrative workflow and a quoted source line rather than a reproduction, and the log above is taken verbatim from a public issue.

How to prevent it

  • Set cache-dependency-path on every repository whose lockfile is not at the root, even before it breaks.
  • Keep actions/checkout as the first step in any job that reads the working tree.
  • Commit lockfiles in anything that is deployed or tested, whatever the library advice says.
  • Match the cache value to the lockfile you have, not to the package manager you used last year.

Frequently asked questions

How do I fix Dependencies lock file is not found in a monorepo?
Set cache-dependency-path on the setup-node step to the lockfile path, relative to the repository root. The default search reads only the top level of the checkout, so a lockfile in packages/app is invisible to it whatever the later steps set working-directory to. A wildcard matching every lockfile in the tree works too, at the cost of a key that changes whenever any package does.
Which lock files does setup-node look for?
It depends on the cache value, and the message prints the list it used. With cache: npm it looks for package-lock.json, then npm-shrinkwrap.json, then yarn.lock. With cache: yarn it looks only for yarn.lock, and with cache: pnpm only for pnpm-lock.yaml. Nothing else is recognized, and no value falls back to another manager's list.
Why does setup-node say some specified paths were not resolved instead?
Because you set cache-dependency-path, which replaces the built-in search with a glob, so there is no filename list left to print. Treat it as the more specific of the two errors: the action looked exactly where you told it to and found nothing, so check the pattern and check that the file is committed.
Do I need to commit package-lock.json for GitHub Actions caching?
Yes, if you want setup-node to cache anything. The cache key is a hash of the lockfile, so a lockfile that is in .gitignore is not in the checkout and there is nothing to hash. It is also what makes npm ci reproducible, so the two requirements point the same way.

Related guides

References

setup-node hands your cache to actions/cache. Latchkey Fast Cache takes the same path and key. Start free → 30-day trial · No credit card