Describe the bug
The Storybook CLI can't tell prerelease Node builds from old ones, and it's blocking storybook info when it shouldn't.
The bug is in how the CLI checks your Node version. In code/core/src/bin/dispatcher.ts, it takes process.versions.node, splits it on the dots, and converts each piece to a number:
const [major, minor, patch] = process.versions.node.split('.').map(Number);
return satisfies(`${major}.${minor}.${patch}`, supportedRange);
Checked against Storybook's supported range (>=20.19.0 <22.0.0 || >=22.12.0), here's what that produces on various Node versions:
"18.20.4" => [18, 20, 4] => false (too old, correctly rejected)
"20.11.1" => [20, 11, 1] => false (below 20.19.0, correctly rejected)
"20.19.0" => [20, 19, 0] => true (correctly accepted)
"20.20.2" => [20, 20, 2] => true (correctly accepted)
"22.9.0" => [22, 9, 0] => false (below 22.12.0, correctly rejected)
"22.22.2" => [22, 22, 2] => true (correctly accepted)
"24.15.0" => [24, 15, 0] => true (correctly accepted)
"26.1.0" => [26, 1, 0] => true (correctly accepted)
"26.1.0-rc.0" => [26, 1, NaN] => false (misfire: should be true)
"24.15.0-nightly20260415abcdef" => [24, 15, NaN] => false (misfire: should be true)
"27.0.0-alpha.1" => [27, 0, NaN] => false (misfire: should be true)
Any version with a tag after the patch number turns that number into NaN. The rebuilt version string becomes unparseable by semver, satisfies() returns false, and the CLI reports a perfectly supported Node version as too old.
Since this check runs before run() is even defined, it applies to every subcommand, including storybook info. On an affected machine, there's no way to run that command to generate the debug output this issue asks for.
Reproduction link
https://github.com/Xevion/storybook-repro-version-parsing
Reproduction steps
git clone
- Build with Docker. The bug is demonstrateable with no components or code, so, the repository is just the Dockerfile.
docker build -t sb-node-prerelease .
docker run --rm sb-node-prerelease
Alternatively, you can test on Linux in just a few seconds by pasting these commands.
curl -sSLO https://nodejs.org/download/rc/v26.1.0-rc.0/node-v26.1.0-rc.0-linux-x64.tar.xz
tar xf node-v26.1.0-rc.0-linux-x64.tar.xz
PATH="$PWD/node-v26.1.0-rc.0-linux-x64/bin:$PATH" npx -y storybook@latest info
# rm -rf ./node-v26.1.0-rc.0-linux-x64{/,.tar.xz}
Produces the following for me:
❯ curl -sSLO https://nodejs.org/download/rc/v26.1.0-rc.0/node-v26.1.0-rc.0-linux-x64.tar.xz
tar xf node-v26.1.0-rc.0-linux-x64.tar.xz
PATH="$PWD/node-v26.1.0-rc.0-linux-x64/bin:$PATH" npx -y storybook@latest info
rm -rf node-v26.1.0-rc.0-linux-x64{/,.tar.xz}
npm warn cli npm v11.13.0 does not support Node.js v26.1.0-rc.0. This version of npm supports the following node versions: `^20.17.0 || >=22.9.0`. You can find the latest version at https://nodejs.org/.
│
■ To run Storybook, you need Node.js version 20.19+ or 22.12+.
│ You are currently running Node.js v26.1.0-rc.0. Please upgrade your Node.js
│ installation.
System
│ Storybook Environment Info:
│
│ System:
│ OS: Linux 7.0 Pop!_OS 22.04 LTS
│ CPU: (16) x64 AMD Ryzen 7 7800X3D 8-Core Processor
│ Shell: 4.2.1 - /home/linuxbrew/.linuxbrew/bin/fish
│ Binaries:
│ Node: 24.19.0 - /home/xevion/.local/share/mise/installs/node/24/bin/node
│ npm: 12.0.2 - /home/xevion/.local/share/mise/installs/npm/latest/package/bin/npm
│ <----- active
│ pnpm: 11.24.0 - /home/xevion/.local/share/mise/installs/pnpm/latest/pnpm
│ Browsers:
│ Chrome: 149.0.7827.53
(Collected after pinning Node to 24, since `storybook info` is itself blocked by the bug.)
Additional context
Passing the raw string to semver instead of reassembling it looks like it would do:
satisfies(process.versions.node, supportedRange, { includePrerelease: true });
includePrerelease is needed because semver otherwise excludes prereleases from ranges that don't name them. It does not loosen the gate:
| version |
plain |
includePrerelease |
| 26.1.0-rc.0 |
false |
true |
| 26.8.0-alpha.0.0.0 |
false |
true |
| 27.0.0-nightly20260902 |
false |
true |
| 24.19.0 |
true |
true |
| 22.11.0 |
false |
false |
| 20.18.0 |
false |
false |
Genuinely unsupported versions still fail.
Describe the bug
The Storybook CLI can't tell prerelease Node builds from old ones, and it's blocking
storybook infowhen it shouldn't.The bug is in how the CLI checks your Node version. In
code/core/src/bin/dispatcher.ts, it takesprocess.versions.node, splits it on the dots, and converts each piece to a number:Checked against Storybook's supported range (
>=20.19.0 <22.0.0 || >=22.12.0), here's what that produces on various Node versions:Any version with a tag after the patch number turns that number into
NaN. The rebuilt version string becomes unparseable by semver,satisfies()returns false, and the CLI reports a perfectly supported Node version as too old.Since this check runs before
run()is even defined, it applies to every subcommand, includingstorybook info. On an affected machine, there's no way to run that command to generate the debug output this issue asks for.Reproduction link
https://github.com/Xevion/storybook-repro-version-parsing
Reproduction steps
git cloneAlternatively, you can test on Linux in just a few seconds by pasting these commands.
Produces the following for me:
System
Additional context
Passing the raw string to semver instead of reassembling it looks like it would do:
includePrereleaseis needed because semver otherwise excludes prereleases from ranges that don't name them. It does not loosen the gate:Genuinely unsupported versions still fail.