pnpm/pnpm · error · PnpmError
INVALID_GIT_COMMIT
INVALID_GIT_COMMIT
Error message
Invalid git commit hash "${resolution.commit}" for repository "${resolution.repo}". Expected a 40-character hexadecimal SHA. What it means
Before touching the network, the git fetcher validates resolution.commit: it must be a full 40-character hexadecimal SHA. Anything else — a branch name like 'main', a tag, or an abbreviated SHA — fails isValidCommitHash. This is both a correctness requirement (checkout needs an immutable ref) and a safety check on the value passed to git.
Source
Thrown at pnpm11/fetching/git-fetcher/src/index.ts:31
import { addFilesFromDir } from '@pnpm/worker'
import { rimraf } from '@zkochan/rimraf'
import { safeExeca as execa } from 'execa'
export interface CreateGitFetcherOptions {
gitShallowHosts?: string[]
storeIndex: StoreIndex
unsafePerm?: boolean
userAgent?: string
ignoreScripts?: boolean
}
export function createGitFetcher (createOpts: CreateGitFetcherOptions): { git: GitFetcher } {
const allowedHosts = new Set(createOpts?.gitShallowHosts ?? [])
const ignoreScripts = createOpts.ignoreScripts ?? false
const gitFetcher: GitFetcher = async (cafs, resolution, opts) => {
if (!isValidCommitHash(resolution.commit)) {
throw new PnpmError('INVALID_GIT_COMMIT', `Invalid git commit hash "${resolution.commit}" for repository "${resolution.repo}". Expected a 40-character hexadecimal SHA.`)
}
const tempLocation = await cafs.tempDir()
try {
if (allowedHosts.size > 0 && shouldUseShallow(resolution.repo, allowedHosts)) {
await execGit(['init'], { cwd: tempLocation })
await execGit(['remote', 'add', 'origin', resolution.repo], { cwd: tempLocation })
await execGit(['fetch', '--depth', '1', 'origin', resolution.commit], { cwd: tempLocation })
} else {
await execGit(['clone', resolution.repo, tempLocation])
}
} catch (err: unknown) {
assert(util.types.isNativeError(err))
throw gitFetchError(err, resolution.repo, opts.pkg?.name)
}
await execGit(['checkout', resolution.commit], { cwd: tempLocation })
const receivedCommit = await execGit(['rev-parse', 'HEAD'], { cwd: tempLocation })
if (receivedCommit.trim() !== resolution.commit) {
throw new PnpmError('GIT_CHECKOUT_FAILED', `received commit ${receivedCommit.trim()} does not match expected value ${resolution.commit}`)View on GitHub (pinned to 5b11d3a15b)
Solutions
- Regenerate the lockfile so the git resolver records the full SHA: rm pnpm-lock.yaml && pnpm install
- Reference git deps by tag or branch in package.json and let pnpm resolve and lock the full SHA
- Never hand-edit resolution.commit fields
Example fix
# before - hand-edited lockfile resolution: commit: main # after - locked full SHA (regenerate the lockfile) resolution: commit: 9f8e7d6c5b4a3928172635445362718990aabbcc
Defensive patterns
Strategy: validation
Validate before calling
const COMMIT_SHA = /^[0-9a-f]{40}$/i
function isFullCommitSha (commit: string | undefined): boolean {
return commit != null && COMMIT_SHA.test(commit)
}
if (!isFullCommitSha(resolution.commit)) {
throw new Error(`resolution.commit must be a 40-char hex SHA, got: ${String(resolution.commit)}`)
} Try / catch
catch code === 'INVALID_GIT_COMMIT'; respond by regenerating the lockfile rather than patching the field by hand
Prevention
- Never hand-edit git resolutions in pnpm-lock.yaml; re-resolve instead
- If tooling rewrites lockfiles, validate commit fields against a 40-hex check afterwards
- Reference git deps by branch/tag in package.json and let pnpm lock the full SHA
When it happens
Trigger: resolution.commit is not a 40-hex SHA: hand-edited lockfiles storing branch or tag names or short SHAs; custom tooling or resolvers emitting non-SHA commits; lockfiles produced by an incompatible pnpm version.
Common situations: Manually 'simplifying' lockfile git entries; scripts that rewrite lockfiles; mixed pnpm versions across a team writing different resolution shapes.
Related errors
- PATCH_FILE_PATH_MISSING
- LICENSES_NO_LOCKFILE
- OUTDATED_NO_LOCKFILE
- GIT_DEP_PREPARE_NOT_ALLOWED
- INVALID_PATH
AI-assisted analysis of pnpm/pnpm@5b11d3a15b (2026-08-16).
Data as JSON: /api/errors/78999d2b5f1072ab.
Report an issue: GitHub.