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

  1. Use a valid channel: nightly, rc, test, v8-canary, or release
  2. For LTS, just use a semver range covering the LTS line (e.g. runtime:20.x) with no channel prefix
  3. 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

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


AI-assisted analysis of pnpm/pnpm@5b11d3a15b (2026-08-16). Data as JSON: /api/errors/5426ab7356a8f2a5. Report an issue: GitHub.