pnpm/pnpm · error · PnpmError
INVALID_NODE_RELEASE_CHANNEL
INVALID_NODE_RELEASE_CHANNEL
Error message
"${releaseChannel}" is not a valid Node.js release channel What it means
Thrown by parseNodeSpecifier when a runtime:node specifier uses the 'channel/version' form but the channel token is not one of nightly, rc, test, v8-canary, or release. The hint lists the valid channels. This is pure input validation before any network access.
Source
Thrown at pnpm11/engine/runtime/node-resolver/src/parseNodeSpecifier.ts:17
import { PnpmError } from '@pnpm/error'
export interface NodeSpecifier {
releaseChannel: string
versionSpecifier: string
}
const RELEASE_CHANNELS = ['nightly', 'rc', 'test', 'v8-canary', 'release']
const isStableVersion = (version: string): boolean => /^\d+\.\d+\.\d+$/.test(version)
export function parseNodeSpecifier (specifier: string): NodeSpecifier {
// Handle "channel/version" format: "rc/18", "rc/18.0.0-rc.4", "release/22.0.0", "nightly/latest"
if (specifier.includes('/')) {
const [releaseChannel, versionSpecifier] = specifier.split('/', 2)
if (!RELEASE_CHANNELS.includes(releaseChannel)) {
throw new PnpmError('INVALID_NODE_RELEASE_CHANNEL', `"${releaseChannel}" is not a valid Node.js release channel`, {
hint: `Valid release channels are: ${RELEASE_CHANNELS.join(', ')}`,
})
}
return { releaseChannel, versionSpecifier }
}
// Exact prerelease version with a recognized release channel suffix.
// e.g. "22.0.0-rc.4", "22.0.0-nightly20250315d765e70802", "22.0.0-v8-canary2025..."
const prereleaseChannelMatch = specifier.match(/^\d+\.\d+\.\d+-(nightly|rc|test|v8-canary)/)
if (prereleaseChannelMatch != null) {
return { releaseChannel: prereleaseChannelMatch[1], versionSpecifier: specifier }
}
// Exact stable version: "22.0.0"
if (isStableVersion(specifier)) {
return { releaseChannel: 'release', versionSpecifier: specifier }
}
View on GitHub (pinned to 5b11d3a15b)
Solutions
- Use a valid channel: nightly, rc, test, v8-canary, or release
- For LTS, just use a semver range covering the LTS line (e.g. runtime:20.x) with no channel prefix
- For stable releases, omit the channel entirely — runtime:22 is already the release channel
Example fix
// before "node": "runtime:stable/22.0.0" // after "node": "runtime:release/22.0.0" // or simply "node": "runtime:22.0.0"
Defensive patterns
Strategy: type-guard
Validate before calling
const RELEASE_CHANNELS = ['nightly', 'rc', 'test', 'v8-canary', 'release']
function assertValidChannel (spec: string): void {
const channel = spec.includes('/') ? spec.split('/')[0] : null
if (channel != null && !RELEASE_CHANNELS.includes(channel)) {
throw new Error(`Invalid channel '${channel}'. Valid: ${RELEASE_CHANNELS.join(', ')}`)
}
} Type guard
const isValidNodeChannel = (channel: string): boolean => ['nightly', 'rc', 'test', 'v8-canary', 'release'].includes(channel)
Try / catch
try {
await install()
} catch (err) {
if (err instanceof PnpmError && err.code === 'INVALID_NODE_RELEASE_CHANNEL') {
// the hint already lists valid channels — drop the invalid prefix or use 'release'
}
throw err
} Prevention
- Remember there is no 'lts'/'stable' channel — use a semver range or 'release'
- Lint package.json for runtime: specifiers with a channel whitelist
- Use 'v8-canary' (not 'canary') for V8 canary builds
When it happens
Trigger: Specifiers like runtime:stable/22, runtime:beta/20, or runtime:lts/18 — anything with a slash whose first segment is not in RELEASE_CHANNELS. Commonly from guessing channel names that nodejs.org does not use.
Common situations: Assuming 'lts' or 'stable' or 'current' are channels (they are not in this API — LTS is a version range, stable is the default 'release' channel); typos like 'canary' instead of 'v8-canary'.
Related errors
- NODEJS_VERSION_NOT_FOUND
- LOGIN_MISSING_CREDENTIALS
- APPROVE_BUILDS_ALL_WITH_ARGS
- CONFIG_SET_AUTH_NON_STRING
- CONFIG_SET_NOT_A_PROJECT_SETTING
AI-assisted analysis of pnpm/pnpm@5b11d3a15b (2026-08-16).
Data as JSON: /api/errors/5426ab7356a8f2a5.
Report an issue: GitHub.