pnpm/pnpm · error · Error

Invalid query - ${query}. List can search only by version or

Error message

Invalid query - ${query}. List can search only by version or range

What it means

When `pnpm list`/`pnpm why` receives a search query containing an `@`-suffixed spec, createPackagesSearcher parses it with npa and only accepts name-only queries (raw equals name) or specs whose type is a semver version or range. Anything else — a dist-tag, git spec, or protocol — is rejected with this plain Error (note: no PnpmError code, so it is not catchable by error code, only by message).

Source

Thrown at pnpm11/deps/inspection/tree-builder/src/createPackagesSearcher.ts:61

  }
  if (packageSelector.matchVersion == null) {
    return true
  }
  return !version.startsWith('link:') && packageSelector.matchVersion(version)
}

interface ParsedSearchQuery {
  matchName: (name: string) => boolean
  matchVersion?: (version: string) => boolean
}

function parseSearchQuery (query: string): ParsedSearchQuery {
  const parsed = npa(query)
  if (parsed.raw === parsed.name) {
    return { matchName: createMatcher(parsed.name) }
  }
  if (parsed.type !== 'version' && parsed.type !== 'range') {
    throw new Error(`Invalid query - ${query}. List can search only by version or range`)
  }
  return {
    matchName: createMatcher(parsed.name),
    matchVersion: (version: string) => semver.satisfies(version, parsed.fetchSpec),
  }
}

View on GitHub (pinned to 5b11d3a15b)

Solutions

  1. Search by name only (`pnpm ls lodash`) — tags cannot be searched because installed trees only carry resolved versions
  2. Use a concrete version or range: `pnpm ls lodash@^4`, `pnpm ls lodash@4.17.21`
  3. If a script builds the query, only append @range when the suffix parses as semver (see validation snippet)
  4. Find what a tag resolves to first: `pnpm view <pkg> dist-tags`

Example fix

# before
pnpm ls typescript@next

# after
pnpm ls typescript   # or: pnpm ls typescript@5.9.0-beta  (a real version/range)
Defensive patterns

Strategy: validation

Validate before calling

import npa from 'npm-package-arg'
import semver from 'semver'

function isSearchableQuery (query: string): boolean {
  try {
    const parsed = npa(query)
    if (parsed.raw === parsed.name) return true           // bare name
    return parsed.type === 'version' || parsed.type === 'range' // name@semver
  } catch {
    return false
  }
}

const queries = params.filter(isSearchableQuery)
if (queries.length === 0) {
  throw new Error(`No searchable queries in: ${params.join(', ')}. Use a name or name@semver-range.`)
}

Type guard

function isListSearchQueryError (err: unknown): boolean {
  // this throw is a plain Error (no PnpmError code) — match on message shape
  return err instanceof Error && /^Invalid query - .+\. List can search only by version or range$/.test(err.message)
}

Try / catch

catch (err) {
  if (isListSearchQueryError(err)) {
    // strip the non-semver suffix and retry with the bare name
    const bareName = query.split('@')[0]
    return runList([bareName])
  }
  throw err
}

Prevention

When it happens

Trigger: `pnpm ls lodash@next` (dist-tag — npa type is 'tag', not version/range), `pnpm why "pkg@git+https://…"`, `pnpm ls "pkg@file:../x"`, `pnpm ls "pkg@http://…"`. Any name@X where X is not a valid semver version/range hits the throw.

Common situations: Trying to filter the dependency tree by dist-tag the same way you would pin in package.json; pasting a dependency spec straight from package.json (git/file/alias specs) into pnpm ls; scripts that append `@${VERSION}` where VERSION is a tag like 'latest' or empty/garbage producing a non-semver suffix.

Related errors


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