DEV Community

Cover image for No pnpm version is specified in pnpm/action-setup
Kay
Kay

Posted on Originally published at latchkey.dev

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" ```

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
Enter fullscreen mode Exit fullscreen mode

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.

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.

Step What the action checks Outcome
1 The version input, when packageManager names a different version Throws Multiple versions of pnpm specified:
2 The version input, otherwise Uses it and stops looking
3 devEngines.packageManager with a name of pnpm Uses its version
4 packageManager, with any integrity hash stripped Uses that version
5 No GITHUB_WORKSPACE in the environment Throws No workspace is found.
6 Nothing left Throws No pnpm version is specified.

Step 3 before step 4 is deliberate: devEngines.packageManager takes priority over packageManager, so a repository that carries both is installing whichever the first one names.

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.
Enter fullscreen mode Exit fullscreen mode

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 ```

The two lines in the middle interpolate whatever your workflow and manifest actually say, so the versions above are placeholders and the rest of the text is fixed.

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.

FAQ

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.

References

Top comments (0)