Skip to content

fix(cli): stop doctor crashing on missing yarn and npm 9+ warnings - #3039

Open
mrpmohiburrahman wants to merge 1 commit into
infinitered:masterfrom
mrpmohiburrahman:fix/doctor-crashes
Open

fix(cli): stop doctor crashing on missing yarn and npm 9+ warnings#3039
mrpmohiburrahman wants to merge 1 commit into
infinitered:masterfrom
mrpmohiburrahman:fix/doctor-crashes

Conversation

@mrpmohiburrahman

@mrpmohiburrahman mrpmohiburrahman commented Aug 19, 2026

Copy link
Copy Markdown

Description

npx ignite-cli doctor throws instead of printing the environment report. It is
the command people run because something is already broken, so it fails exactly
when it is needed.

#3024 has two reporters with two different stack traces. They are independent bugs
that happen to sit behind the same command, so fixing one still leaves the other
person crashing — that is why this is one PR.

Problem

1. Crash when yarn is not installed (reported by @xx1906, Windows 10)

TypeError: Cannot read properties of null (reading 'split')
    at Command.<anonymous> (...\ignite-cli\build\commands\doctor.js:49:59)

which("yarn") returns null when yarn is absent, so yarnVersion short-circuits
to null — but the .split(".") on the next line sits outside the yarnPath &&
guard that protects the line above it:

const yarnVersion = yarnPath && (await run("yarn --version", { trim: true }))
const yarnMajorVersion = parseInt(yarnVersion.split(".")[0], 10)   // <- throws

This arrived with the yarn 4 support in #2913. It does not reproduce on a typical
Mac setup, which is why it looked unreproducible — macOS almost always has yarn
present via corepack.

2. Crash parsing npm output (reported by @pietrofxq, Linux, Node 24)

SyntaxError: Unexpected token 'p', "npm warn Un"... is not valid JSON
    at JSON.parse (<anonymous>)
    at .../ignite-cli/build/tools/packager.js:193:35

packager.list() strips npm's warning lines before JSON.parse, but the regex only
matched the legacy uppercase npm WARN. npm 9+ emits lowercase npm warn, which
survives the strip and gets handed to the parser along with the JSON.

Solution

Two one-line changes.

src/commands/doctor.ts — derive the major version only when there is a version to
derive it from. The four things downstream already handle absence (=== 1 is falsy,
column2 renders -, column3 renders not installed), so the guard belongs at
the derivation rather than at every call site:

-const yarnMajorVersion = parseInt(yarnVersion.split(".")[0], 10)
+const yarnMajorVersion = yarnVersion ? parseInt(yarnVersion.split(".")[0], 10) : undefined

src/tools/packager.ts — make the warning strip case-insensitive. The prepended-warning
strategy documented in the comment above it is deliberate and unchanged; only the casing
was wrong:

-const json = JSON.parse(output.replace(/npm WARN.+/g, ""))
+const json = JSON.parse(output.replace(/npm warn.+/gi, ""))

Testing

Both crashes were reproduced locally first, then confirmed gone.

Missing yarn — running doctor with a PATH containing node but not yarn threw
the reported TypeError before the change. After it, the full report prints and the
command exits 0, with the existing rendering preserved:

JavaScript
  node               22.13.1      /.../node
  npm                -            not installed
  yarn               -            not installed
  pnpm               -            not installed
  bun                -            not installed

With yarn present the output is byte-identical to before the change — I captured
doctor on the patched tree, stashed the two fixes, captured it again, and diffed.
No difference, both exit 0. That is what shows the guard is purely additive rather
than quietly changing what the table reports.

npm warnings — added a regression test to the existing src/tools/packager.test.ts
covering lowercase npm warn. I checked it genuinely fails on the old regex rather than
passing either way:

OLD /npm WARN.+/g   -> SyntaxError: Unexpected token 'p', "npm warn Un"... is not valid JSON
NEW /npm warn.+/gi  -> [["ignite-cli", "11.5.0"]]

The two existing uppercase npm WARN tests in that file still pass, so older npm output
is unaffected. A live doctor run also parsed real npm list --global --json output from
npm 10.9.2 through the changed function.

Suite: 7 of 8 suites pass (40 of 41 tests), plus typecheck, format:check and
depcruise clean. The one failure, ignite-new.test.ts › --packager=yarn, fails
identically on master with these changes stashed, so it is pre-existing and not something
this PR introduces.

I did not add a unit test for the doctor path itself — there is no command-level test
harness in the repo and no jest.mock anywhere, so covering it would mean introducing a
mocking pattern that does not exist yet. Happy to add one if you would like it.

Follow-ups (not in this PR)

Two adjacent things I noticed and deliberately left alone to keep this a small crash fix —
happy to open issues or separate PRs if useful:

  • doctor.ts:54run("yarn --version") is unguarded and gluegun's run throws on a
    non-zero exit. Inside any project whose packageManager field names something other than
    yarn, corepack refuses to run yarn and doctor still exits 1. This is the line above
    the one changed here, so it is untouched by this PR.

  • doctor.ts:58 — pnpm is only probed when yarn v1 is present (if (yarnMajorVersion === 1)),
    so a pnpm-only machine reports pnpm as "not installed". Slightly odd now that Use and recommend pnpm instead of yarn #3016 moved
    the repo itself onto pnpm.

  • Issues: fixes npx ignite-cli doctor throw error #3024

Checklist

  • I have manually tested this — reproduced both crashes on a local clone, confirmed both
    are fixed, and verified doctor's output is byte-identical when yarn is present
    (see docs).

`doctor` threw instead of printing its report, for two independent reasons
reported by two people in infinitered#3024.

When yarn is not installed, `which("yarn")` returns null and `yarnVersion`
short-circuits to null, but the `.split(".")` deriving `yarnMajorVersion` sat
outside the `yarnPath &&` guard protecting the line above it. Guard the
derivation; all four downstream consumers already tolerate absence.

Separately, the npm global-package listing strips warning lines before
`JSON.parse`, but the regex only matched the legacy uppercase `npm WARN`.
npm 9+ emits lowercase `npm warn`, which survived the strip and reached the
parser. Make the strip case-insensitive; the existing strategy is unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

npx ignite-cli doctor throw error

1 participant