pnpm.ts's `parseInfoResult` doesn't unwrap npm 12's array-wrapped · Issue #2274 · changesets/changesets · GitHub
Skip to content

pnpm.ts's parseInfoResult doesn't unwrap npm 12's array-wrapped #2274

Closed

Description

@edoardocavazza

Summary

changeset publish crashes with pnpm as the package manager, in any environment where the underlying npm binary is npm 12+ (e.g. after a npm install -g npm@latest step in CI, which is common right before a release job):

TypeError: Cannot read properties of undefined (reading 'includes')
at getUnpublishedPackages (.../@changesets/cli/dist/getPublishPlan.mjs:613:26)
at process.processTicksAndRejections (node:internal/process/task_queues:104:5)
at async getPublishPlan (.../getPublishPlan.mjs:665:19)
at async publish (.../publish.mjs:70:96)

Root cause

On pnpm ≤10, pnpm info/pnpm view is not a native pnpm command — it's passed straight through to the system's npm binary (see pnpm/src/pnpm.ts, the passThruToNpm() case list includes info/view). So pnpm info <pkg> --json on pnpm 10.x is really just npm view <pkg> --json under the hood, using whatever npm is currently resolvable on PATH (packages exec/run-npm/src/index.ts: const npm = npmPath ?? 'npm').

npm 12.0.0 changed npm view <pkg> --json to always wrap its result in an array ([ {...} ]) instead of returning a bare object — this is exactly what #2164 reported and was fixed for, in the pre-v3 npm-utils.ts's getPackageInfo().

That fix correctly carried over into the new npm.ts after the publish-flow split in #2155 (parseInfoResult$1/the npm tool's parseInfoResult explicitly does Array.isArray(parsed) ? { info: parsed[0] } : { info: parsed }), but the equivalent guard was not added to the new pnpm.ts's parseInfoResult:

// packages/cli/src/lib/pnpm.ts
function parseInfoResult({ exitCode, stdout, stderr }) {
  if (exitCode !== 0) return { error: getPnpmError(stderr, stdout) }
  return stdout ? { info: JSON.parse(stdout) } : undefined   // <-- no array unwrap
}

Since pnpm ≤10 delegates to the same underlying npm view, it hits the exact same npm-12 array-wrapping — but because pnpm.ts's parser stores the array as-is in response.info, response.info.versions is undefined, and getUnpublishedPackages crashes calling .includes() on it in getPublishPlan.ts.

Reproduction

  • @changesets/cli 3.0.1
  • Any pnpm ≤10 (tested 10.33.0)
  • npm 12.0.0+ resolvable on PATH (e.g. right after npm install -g npm@latest)
  • Publish a package that's already on the registry (or run changeset publish with no changesets) → crash instead of "already published" / "no unpublished projects" message.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions