Skip to content
Latchkey LogoLatchkey home

No pnpm version is specified in pnpm/action-setup

No pnpm version is specified is thrown after pnpm/action-setup has looked in three places and found a version in none of them. It is not a network failure and not a registry problem: the action never reached the point of installing anything, because it did not know what to install.

The version lookup order in the action and the three different errors each dead end throws
One function decides all three outcomes. Quoted from src/install-pnpm/run.ts: the throw reads "No pnpm version is specified."

What this error means

The step fails in seconds, before any download, with a five-line message: a headline, one line of instruction, and a bullet for each of the three places it looked. Nothing has been installed, so pnpm is not on the path and every later step that uses it fails too, usually with a command-not-found that sends people to the wrong page. The message is fixed text with no interpolation, so it reads identically in every repository. Two of its three bullets mention package.json, which is the hint: the action almost always failed because it could not read that file, not because the file lacks a field.

pnpm/action-setup, src/install-pnpm/run.ts
No pnpm version is specified.
Please specify it by one of the following ways:
  - in the GitHub Action config with the key "version"
  - in the package.json with the key "packageManager"
  - in the package.json with the key "devEngines.packageManager"

The order the action resolves a version in

All of this happens in one function, readTargetVersion in src/install-pnpm/run.ts. It reads the manifest first if it can, then works down a list, and the message you get depends entirely on where it stopped. Reading the order explains why adding packageManager sometimes fixes nothing and why adding version sometimes breaks a working workflow.

StepWhat the action checksOutcome
1The version input, when packageManager names a different versionThrows Multiple versions of pnpm specified:
2The version input, otherwiseUses it and stops looking
3devEngines.packageManager with a name of pnpmUses its version
4packageManager, with any integrity hash strippedUses that version
5No GITHUB_WORKSPACE in the environmentThrows No workspace is found.
6Nothing leftThrows No pnpm version is specified.

Common causes

actions/checkout has not run yet

The common one, and the one the message actively disguises. The action reads package.json from the workspace, the read fails because nothing has been checked out, and that failure is swallowed on purpose so a repository with no manifest still works. What is left is a lookup with nothing in it.

The repository genuinely declares no pnpm version

No version input, no packageManager, no devEngines.packageManager. The action does not guess, which is the right call: a silently chosen version is how a lockfile gets rewritten by a major nobody selected.

The manifest is not at the workspace root

A monorepo where the root has no package.json, or one where it sits under a subdirectory. The action looks at the path in package_json_file, which defaults to package.json and is documented as relative to the repository root, so a manifest elsewhere is simply not seen.

The field exists but is not in a form the action accepts

A packageManager value that names something other than pnpm is ignored, because the action checks that the string starts with the pnpm prefix before it takes anything from it. A devEngines.packageManager entry whose name is not pnpm is skipped for the same reason.

How to fix it

Check the step order before you edit package.json

  1. Look at the job in the run, not at the repository, and find whether actions/checkout ran before the pnpm step.
  2. If it did not, move it above and re-run; nothing else needs to change.
  3. If it did, open the manifest the action would have read and confirm it declares a version in one of the two fields.

Pin the version in the manifest

The better default for a repository with developers on it, because their local tooling reads the same field. Set it once and the workflow needs no version at all.

package.json (illustrative)
{
  "name": "example",
  "packageManager": "pnpm@10.9.8"
}

Or pin it on the step, and then only there

Use the version input when there is no manifest to carry the value. Do not set both unless they agree, since a disagreement is the Multiple versions of pnpm specified: error rather than a precedence rule.

Point the action at the manifest when it is not at the root

Give package_json_file a path relative to the workspace root. This is the monorepo answer, and it keeps the version in one file rather than repeating it across every workflow that needs pnpm.

.github/workflows/ci.yml (illustrative)
      - uses: actions/checkout@v7
      - uses: pnpm/action-setup@v6
        with:
          package_json_file: packages/app/package.json

A workflow that produces it

This file is written for this page and has never been run. It is the shape that produces the error most often, and the defect is the missing checkout rather than anything about pnpm. Without it the workspace is empty, the read of package.json fails with a not-found that the action deliberately swallows, and the lookup falls all the way through to step six.

.github/workflows/ci.yml (illustrative)
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: pnpm/action-setup@v6
      - uses: actions/checkout@v7
      - run: pnpm install

Why a missing checkout does not say so

There is a message for a missing workspace, and it would be the useful one here, but it almost never fires on GitHub-hosted runners. The action only throws No workspace is found. when the GITHUB_WORKSPACE environment variable is absent entirely, and the runner always sets it, even when the directory it points at is empty. A missing or late actions/checkout therefore lands on step six instead of step five.

That is worth knowing, because the message it does throw sends you to package.json to add a field that is already there in the repository you are looking at. The file is simply not on disk yet at the moment the action reads it.

pnpm/action-setup, src/install-pnpm/run.ts
No workspace is found.
If you've intended to let pnpm/action-setup read preferred pnpm version from the "packageManager" field in the package.json file,
please run the actions/checkout before pnpm/action-setup.
Otherwise, please specify the pnpm version in the action configuration.

The opposite error, which looks like this one

If both the version input and packageManager are set and they disagree, the action refuses rather than choosing, and the message begins with a header that is easy to mistake for the one on this page. It names both values and both sources, so it is unambiguous once you read past the first line:

pnpm/action-setup, src/install-pnpm/run.ts (values illustrative)
Multiple versions of pnpm specified:
  - version 9 in the GitHub Action config with the key "version"
  - version pnpm@10.9.8 in the package.json with the key "packageManager"
Remove one of these versions to avoid version mismatch errors like ERR_PNPM_BAD_PM_VERSION

Which field to reach for

The README is direct about when the input is optional: version is "Optional when there is a [packageManager or devEngines.packageManager field in the package.json]", and "otherwise, this field is required". It accepts more than an exact pin, listing "an exact version (such as 10.9.8), or a version range (such as 10, 10.x.x, 10.9.x, ^10.9.8, *, etc.), or latest".

Prefer the manifest field when your developers already have one, because it is the same value their local tooling reads and there is then only one number to bump. The action strips an integrity suffix for you, so a packageManager of the form pnpm@10.9.8+sha512... resolves to the version before the plus. If the repository has no package.json at the root, or the one it has is somewhere else, the package_json_file input takes a path relative to the workspace root.

.github/workflows/ci.yml (illustrative)
      - uses: actions/checkout@v7
      - uses: pnpm/action-setup@v6
        with:
          version: 10
      - uses: actions/setup-node@v7
        with:
          node-version: 22
          cache: pnpm

Why there is no recorded run on this page

The error is thrown by a pure function reading two inputs and a file, before the action spawns a process or touches the network. There is nothing for a runner to influence and nothing transient to catch, so a recorded run would be a screenshot of a string this page already quotes from the line that throws it. The workflows above are illustrative, and the message text is quoted from the action's source at the current major.

How to prevent it

  • Put actions/checkout first in every job that sets up a package manager from the manifest.
  • Keep the pnpm version in one place, and make that place packageManager if developers run pnpm locally.
  • Never set both version and packageManager to different values, since the action refuses rather than choosing.
  • Order actions/setup-node with cache: pnpm after the pnpm step, so the cache path resolves against the version you asked for.

Frequently asked questions

Why does pnpm/action-setup say no version when package.json has packageManager?
Because it read the workspace before actions/checkout put the file there. The read fails with a not-found that the action swallows deliberately, so the lookup ends with nothing and throws this message. Move the checkout above the pnpm step and the same manifest resolves.
Does devEngines.packageManager override packageManager for pnpm?
Yes. The action checks devEngines.packageManager before packageManager, and takes its version when the name is pnpm. A repository carrying both installs whatever devEngines names, so if the two have drifted apart the second one is doing nothing.
What does "Multiple versions of pnpm specified" mean?
That the version input and the packageManager field both exist and name different versions. The action refuses to pick and tells you to remove one, naming the mismatch error it is trying to save you from. It is the opposite condition to this page, not a variant of it.
Can I give pnpm/action-setup a version range instead of an exact version?
Yes. Its README lists an exact version such as 10.9.8, a range such as 10, 10.x.x, 10.9.x, ^10.9.8 or *, and latest. A packageManager field is exact by specification, so a range has to go in the version input, and then the field must not disagree with it.

Related guides

References

A cold pnpm store is the slowest part of the job. Latchkey Fast Cache restores it in one request. Start free → 30-day trial · No credit card