pnpm/pnpm · error · PnpmError

STARS_UNAUTHORIZED

STARS_UNAUTHORIZED

Error message

You must be logged in to list your starred packages

What it means

`pnpm stars` with no username argument must resolve your identity via whoami, which requires credentials; when getAuthHeaderForRegistry finds no token for the default registry, the handler throws STARS_UNAUTHORIZED client-side before any HTTP request. Passing an explicit username skips whoami entirely, so listing another user's stars needs no login.

Source

Thrown at pnpm11/registry-access/commands/src/star/stars.ts:30

export const commandNames = ['stars']

export function help (): string {
  return renderHelp({
    description: 'Lists all packages starred by a specific user.',
    url: docsUrl('stars'),
    usages: ['pnpm stars [<user>]'],
  })
}

export async function handler (opts: StarOptions, params: string[]): Promise<string> {
  const registryUrl = normalizeRegistryUrl(opts.registriesByScope?.default ?? 'https://registry.npmjs.org/')
  const fetchFromRegistry = createFetchFromRegistry(opts)
  const authHeader = getAuthHeaderForRegistry(opts.configByUri, registryUrl)

  let username = params[0]
  if (!username) {
    if (!authHeader) {
      throw new PnpmError('STARS_UNAUTHORIZED', 'You must be logged in to list your starred packages')
    }
    username = await fetchWhoami(registryUrl, fetchFromRegistry, authHeader)
  }

  if (!params[0]) {
    const starUrl = new URL('./-/user/v1/star', registryUrl).href
    const response = await fetchFromRegistry(starUrl, {
      authHeaderValue: authHeader,
    })
    if (response.ok) {
      const starsData = await response.json() as string[] | Record<string, unknown>
      if (Array.isArray(starsData)) return starsData.join('\n')
      if (typeof starsData === 'object' && starsData !== null) {
        return Object.keys(starsData).join('\n')
      }
    }
  }

View on GitHub (pinned to 6261b7f388)

Solutions

  1. Pass a username explicitly: `pnpm stars <user>` — no authentication needed for other users' stars
  2. Or log in first: `pnpm login` (add --registry=<url> if your default registry is private), then `pnpm stars`
  3. Verify the token is picked up with `pnpm whoami` before scripting `pnpm stars`

Example fix

# before
pnpm stars            # not logged in -> STARS_UNAUTHORIZED

# after
pnpm stars isaacs     # explicit user: no login required
Defensive patterns

Strategy: validation

Validate before calling

import { getAuthHeaderForRegistry } from '...' // registry-access star common

const registryUrl = normalizeRegistryUrl(opts.registriesByScope?.default ?? 'https://registry.npmjs.org/')
if (!params[0] && !getAuthHeaderForRegistry(opts.configByUri, registryUrl)) {
  throw new Error('Pass a username (`pnpm stars <user>`) or log in first (`pnpm login`)')
}
await starsHandler(opts, params)

Type guard

import util from 'node:util'
import { PnpmError } from '@pnpm/error'

function isStarsUnauthorized (err: unknown): err is PnpmError {
  return util.types.isNativeError(err) && (err as PnpmError).code === 'STARS_UNAUTHORIZED'
}

Try / catch

catch (err) {
  if (isStarsUnauthorized(err)) {
    // client-side check: nothing was sent — prompt login, or ask for an explicit username
    const user = await promptUsername()
    return await starsHandler(opts, [user]) // explicit user needs no auth
  }
  throw err
}

Prevention

When it happens

Trigger: `pnpm stars` on a machine with no token for the default registry; a private default registry that was never logged into; CI containers without credentials asking for the caller's own stars.

Common situations: Fresh environments; users who authenticate only per-scope for publishing; scripts running `pnpm stars` without checking login state first.

Related errors


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