pnpm/pnpm · error · PnpmError

DIST_TAG_ADD_INVALID_VERSION

DIST_TAG_ADD_INVALID_VERSION

Error message

Version must be an exact semver version, got "${version}"

What it means

The version part of the dist-tag add spec failed semver.valid(): dist-tags must reference one concrete version, so ranges (^1.0.0, ~1.2, 1.x) and partials (1.2) are rejected. The offending value is embedded in the message. Thrown before any registry access.

Source

Thrown at pnpm11/registry-access/commands/src/distTag.ts:145

  return lines.join('\n')
}

async function distTagAdd (
  opts: DistTagOptions,
  params: string[]
): Promise<string> {
  if (params.length === 0) {
    throw new PnpmError('DIST_TAG_ADD_SPEC_REQUIRED', 'Package name and version are required (e.g., pnpm dist-tag add pkg@1.0.0 latest)')
  }

  const { name: packageName, versionRange: version } = parsePackageSpec(params[0])

  if (!version) {
    throw new PnpmError('DIST_TAG_ADD_VERSION_REQUIRED', 'Version is required (e.g., pnpm dist-tag add pkg@1.0.0 latest)')
  }

  if (!semver.valid(version)) {
    throw new PnpmError('DIST_TAG_ADD_INVALID_VERSION', `Version must be an exact semver version, got "${version}"`)
  }

  const tag = params[1] ?? 'latest'

  const registryUrl = pickRegistryForPackage(opts.registriesByScope ?? { default: 'https://registry.npmjs.org/' }, packageName)
  const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl, packageName)
  const fetchFromRegistry = createFetchFromRegistry(opts)
  const cliOtp = opts.cliOptions?.otp
  const authType = cliOtp ? 'legacy' : 'web'

  await withOtpHandling({
    context: createOtpContext(opts),
    fetchOptions: WEB_AUTH_FETCH_OPTIONS,
    operation: (otp) => setDistTag({
      packageName,
      version,
      distTag: tag,
      registryUrl,

View on GitHub (pinned to 6261b7f388)

Solutions

  1. Pin an exact version: pnpm dist-tag add mypkg@1.4.0 next
  2. Resolve the range first: pnpm view mypkg@^1.0.0 version, then use the printed version

Example fix

# before - a range is not an exact version
pnpm dist-tag add mypkg@^1.0.0 next

# after
pnpm view mypkg@^1.0.0 version   # prints 1.4.0
pnpm dist-tag add mypkg@1.4.0 next
Defensive patterns

Strategy: validation

Validate before calling

import semver from 'semver'

const version = splitSpec(params[0] ?? '').version
if (!(version != null && semver.valid(version) != null)) {
  throw new Error('dist-tag add needs an exact version like 1.4.0, got: ' + version)
}

Type guard

import semver from 'semver'

const isExactVersion = (v: string | undefined): v is string =>
  v != null && semver.valid(v) != null

Prevention

When it happens

Trigger: pnpm dist-tag add mypkg@^1.0.0 next; pnpm dist-tag add mypkg@1.2 latest; copy-pasting a semver range from package.json dependencies as the version.

Common situations: Pasting a dependency range where a version belongs; scripting with a range or alias instead of a resolved concrete version.

Related errors


AI-assisted analysis of pnpm/pnpm@6261b7f388 (2026-08-17). Data as JSON: /api/errors/e14bc67c1e12261e. Report an issue: GitHub.