790 words
4 minutes

pnpm root -g Prints a Warning Before the Path: Fix CI Parsers

2026-08-09
DevOps
pnpm
/
DevOps
/
CLI
/
Troubleshooting

If a script expects pnpm root -g to print one directory but receives a warning followed by the path, the parser is reading a human-facing message from stdout. pnpm 12.0.0-rc.1 moves warnings from pnpm root -g and pnpm bin -g to stderr and adds support for pnpm root -g and pnpm prefix -g. Treat that release as a test target, not an automatic production upgrade, because it is still a release candidate.

The durable fix is to make the boundary explicit: validate that the command produced one path, keep diagnostics on a separate stream, and pin the pnpm version used by CI. Do not “fix” the failure by taking the first line of arbitrary CLI output.

What broke in pnpm 11#

The pnpm issue that exposed this problem used a project declaring packageManager: "[email protected]". In that environment, pnpm root -g printed a warning and then the global module path on stdout. A consumer that expected a single path could store the warning as the root, or pass both lines to a later filesystem command.

Reproduce the boundary without exposing credentials:

Terminal window
pnpm --version
pnpm root -g > pnpm-root.stdout 2> pnpm-root.stderr
sed -n '1,5p' pnpm-root.stdout
sed -n '1,5p' pnpm-root.stderr

The exact warning text and global directory depend on the pnpm version and platform. The important observation is which stream contains each line, not the absolute path on one developer’s machine.

Make the parser fail safely#

If you must support a pnpm version that mixes reporter output into stdout, reject anything other than one non-empty path. This turns a silent wrong-directory install into an actionable CI failure:

Terminal window
set -eu
root_output="$(pnpm root -g 2>pnpm-root.stderr)"
root_lines="$(printf '%s\n' "$root_output" | sed '/^[[:space:]]*$/d' | wc -l | tr -d ' ')"
if [ "$root_lines" -ne 1 ] || [ ! -d "$root_output" ]; then
printf '%s\n' 'pnpm root -g did not return one existing directory:' >&2
printf '%s\n' "$root_output" >&2
cat pnpm-root.stderr >&2
exit 1
fi
printf 'Global root: %s\n' "$root_output"

This guard deliberately fails on the affected behavior because the output is ambiguous. It also catches a changed path format before a later command writes to the wrong location. If the command is only used for a human diagnostic, do not parse it at all.

Test the pnpm 12 RC separately#

The pnpm 12.0.0-rc.1 release is the first useful verification target for the stream change. Pin it in an isolated job or temporary checkout:

Terminal window
corepack [email protected] --version
corepack [email protected] root -g > pnpm-root.stdout 2> pnpm-root.stderr
cat pnpm-root.stdout
cat pnpm-root.stderr >&2

The expected shape is one path on stdout and any warning on stderr. Test both root -g and the command your automation actually uses, such as bin -g or prefix -g; a passing smoke test for one command does not prove that every reporter path has the same contract.

When you compare the RC with your current pnpm version, record the result in CI logs without printing private registry configuration. Then run the real install with the project’s lockfile:

Terminal window
corepack [email protected] install --frozen-lockfile

Keep the release candidate pinned in that test job. If the repository is not intentionally evaluating pnpm 12, keep the current version and use the output validation above until the project approves a stable upgrade.

Prefer configuration over global path scraping#

Many scripts use pnpm root -g to locate globally installed CLIs. Before adding more parsing, ask whether the tool can be a project dependency and invoked through pnpm exec. A local dependency gives CI a lockfile-visible version and removes the need to discover a machine-wide directory:

Terminal window
pnpm add --save-dev some-cli
pnpm exec some-cli --version

If a tool must remain global, keep the global-path check in one small wrapper and test it on every supported pnpm version. Do not put a global path into a committed lockfile, and do not assume that the path is shared across macOS, Windows, Linux, containers, or Corepack installations.

This is the same reproducibility boundary that matters when pnpm installs Git dependencies in CI. The pnpm Git dependency guide covers the related URL and credential contract.

FAQ#

Does redirecting stderr fix the old pnpm output?#

Not if the warning is already being written to stdout. Redirecting stderr only captures diagnostics that are actually sent to stderr; it cannot remove a warning that is mixed into the value stream. Validate the output or upgrade after testing the newer behavior.

Is pnpm 12.0.0-rc.1 safe for every project?#

No. It is a release candidate. Use it in a deliberate compatibility job, compare the install and lockfile behavior, and keep production on the version your project has approved until the upgrade is complete.

Why not use head -1 to get the path?#

Because the first line may be a warning today and a different diagnostic tomorrow. A one-line-and-directory check fails loudly when the output contract changes instead of selecting a plausible but incorrect path.

References:

pnpm 12.0.0-rc.1 release notes

pnpm issue: warnings from pnpm root -g on stdout

pnpm install documentation

Git URL rewriting with insteadOf

pnpm root -g Prints a Warning Before the Path: Fix CI Parsers
https://laplusda.com/en/posts/pnpm-root-global-machine-readable-output/
Author
Zero
Published at
2026-08-09
License
CC BY-NC-SA 4.0
Was this article useful?

Report a typo or broken link, or suggest a related topic.