pnpm/pnpm · error · UnexpectedStoreError

UNEXPECTED_STORE

UNEXPECTED_STORE

Error message

Unexpected store location

What it means

node_modules/.modules.yaml records the store directory the packages were hard-linked from. checkCompatibility compares it with the currently resolved store using path.relative (the only correct way to compare paths on Windows, per the linked issue) and also tolerates the legacy '.../v3' sibling store. A missing recorded store or a different location aborts the install because linking from a different store would break the hard-link layout.

Source

Thrown at pnpm11/installing/deps-installer/src/install/checkCompatibility/index.ts:31

    storeDir: string
    modulesDir: string
    virtualStoreDir: string
  }
): void {
  if (!modules.layoutVersion || modules.layoutVersion !== LAYOUT_VERSION) {
    throw new ModulesBreakingChangeError({
      modulesPath: opts.modulesDir,
    })
  }
  // Important: comparing paths with path.relative()
  // is the only way to compare paths correctly on Windows
  // as of Node.js 4-9
  // See related issue: https://github.com/pnpm/pnpm/issues/996
  if (
    !modules.storeDir ||
    path.relative(modules.storeDir, opts.storeDir) !== '' && path.relative(modules.storeDir, path.join(opts.storeDir, '../v3')) !== ''
  ) {
    throw new UnexpectedStoreError({
      actualStorePath: opts.storeDir,
      expectedStorePath: modules.storeDir,
      modulesDir: opts.modulesDir,
    })
  }
  if (modules.virtualStoreDir && path.relative(modules.virtualStoreDir, opts.virtualStoreDir) !== '') {
    throw new UnexpectedVirtualStoreDirError({
      actual: opts.virtualStoreDir,
      expected: modules.virtualStoreDir,
      modulesDir: opts.modulesDir,
    })
  }
}

View on GitHub (pinned to 5b11d3a15b)

Solutions

  1. Run `pnpm install --force` to re-link node_modules from the current store
  2. If the store moved for a reason you control, restore the previous `store-dir` setting instead
  3. Set an explicit shared `store-dir` (CI, Docker volume) so the resolved path never drifts
  4. As a last resort, delete node_modules and reinstall

Example fix

# before: store location changed after editing store-dir
pnpm install   # ERR_PNMP_UNEXPECTED_STORE

# after: either restore the old store path or force a re-link
pnpm config set store-dir /previous/store/path   # option A
pnpm install --force                               # option B
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'fs'
import { join, relative } from 'path'
import { parse } from 'yaml'
import { execSync } from 'child_process'

// Verify the store that built node_modules is the store pnpm resolves now
export function storeMatches (lockfileDir: string): boolean {
  const modules = parse(readFileSync(join(lockfileDir, 'node_modules', '.modules.yaml'), 'utf8')) as { storeDir?: string }
  const currentStore = execSync('pnpm store path', { encoding: 'utf8' }).trim()
  return modules.storeDir != null && (
    relative(modules.storeDir, currentStore) === '' ||
    relative(modules.storeDir, join(currentStore, '../v3')) === ''
  )
}

Type guard

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

export const isUnexpectedStoreError = (err: unknown): err is PnpmError =>
  util.types.isNativeError(err) && (err as PnpmError).code === 'UNEXPECTED_STORE'

Try / catch

try {
  await mutateModules(mutations, opts)
} catch (err) {
  if (isUnexpectedStoreError(err)) {
    // err.expected is the recorded store dir; re-point config there, or purge and retry
    await rimraf(join(opts.lockfileDir, 'node_modules'))
    return mutateModules(mutations, opts)
  }
  throw err
}

Prevention

When it happens

Trigger: Install into node_modules where the recorded storeDir is set but matches neither the current store path nor path.join(storeDir, '../v3') via path.relative, or modules.storeDir is absent.

Common situations: Changed `store-dir` in .npmrc or pnpm-workspace.yaml; a different HOME/user running the install (the default store lives under the user's home); project moved between CI runners or containers with different mount points or drives.

Related errors


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