What this error means
“fatal: pack has bad object” indicates a corrupted pack file in .git/objects/pack. Git cannot read one or more objects, breaking operations like fetch, log, or checkout.
Common causes:
- Interrupted fetch/clone or power loss while writing packs
- Disk or filesystem errors
- Antivirus/sync tools locking or modifying .pack/.idx
- Broken alternates or partial/shallow clones
Quickstart (safe defaults)
If you have no unpushed work, recloning is fastest. If you do, follow:
# 1) Back up your working tree (protect uncommitted files)
rsync -a --exclude='.git' . ../repo-backup-$(date +%s)/
# 2) Identify corrupt packs
git fsck --full --strict || true
# 3) Move suspected pack(s) out of the way; re-fetch clean objects
mkdir -p .git/objects/pack/quarantine
for p in .git/objects/pack/pack-*.pack; do
git verify-pack -v "$p" >/dev/null 2>&1 || mv "$p" "${p/.pack/.idx}" .git/objects/pack/quarantine/ 2>/dev/null || true
# Move idx too if present
[ -f "${p%.pack}.idx" ] && mv "${p%.pack}.idx" .git/objects/pack/quarantine/ || true
done
# 4) Re-download objects
git fetch --all --prune --force --tags
# 5) Repack and clean
git repack -Ad -l
git gc --prune=now
# 6) Verify
git fsck --full --strict
If fsck still fails, consider a fresh clone and cherry-pick local changes from your backup directory.
Minimal working example (reproduce and fix)
This demo corrupts a disposable repo, triggers the error, then fixes it.
set -euo pipefail
# Create a bare remote and a working clone
rm -rf /tmp/git-pack-demo
mkdir -p /tmp/git-pack-demo
cd /tmp/git-pack-demo
git init --bare remote.git
git clone remote.git work
cd work
echo hello > file.txt
git add file.txt
git commit -m "init"
git push origin HEAD:main
# Ensure we have a pack
git gc --aggressive --prune=now
pack=$(ls .git/objects/pack/pack-*.pack | head -n1)
# Intentionally corrupt the pack (flip one byte)
printf '\0' | dd of="$pack" bs=1 seek=128 count=1 conv=notrunc status=none || true
# Observe failure
set +e
git fsck --full; status=$?
set -e
[ $status -eq 0 ] && { echo "unexpected: fsck passed"; exit 1; }
echo "Fixing..."
# Isolate bad pack and refetch from remote
mkdir -p .git/objects/pack/quarantine
mv "${pack%.pack}.pack" "${pack%.pack}.idx" .git/objects/pack/quarantine/
git fetch --all --prune --force --tags
git repack -Ad -l
git fsck --full --strict
Step-by-step diagnosis and repair
- Confirm corruption
- Run: git fsck --full --strict
- Note any bad object IDs or pack names.
- Check for alternates or partial clones
- If .git/objects/info/alternates exists and points to a missing path, remove the invalid line and refetch.
- For shallow clones: git fetch --unshallow or reclone if practical.
- For partial clones: run an unfiltered fetch, then repack: git fetch --filter=blob:none --refetch --repack; or simply git fetch --all and git repack -Ad -l.
- Isolate and replace corrupt packs
- Verify packs individually: git verify-pack -v .git/objects/pack/pack-XXXX.pack
- Move any failing .pack and matching .idx to a quarantine folder.
- Fetch to restore missing objects: git fetch --all --prune --force --tags
- Rebuild repository storage
- Repack and prune packed objects: git repack -Ad -l
- Clean up: git gc --prune=now
- Verify again: git fsck --full --strict
- Salvage unpushed work if repairs fail
- Copy the working tree (excluding .git) to a safe location; you can re-add these files to a fresh clone.
- If commits exist locally but refs are broken, try: git show <sha> or git cat-file -p <sha> for reachable objects; otherwise, patch from backup copy.
Server/bare repository guidance
- Run on the server:
- git fsck --full --strict
- git verify-pack -v .git/objects/pack/pack-*.pack | less
- Move failing packs aside; git fetch from an upstream mirror if available.
- Repack for efficient serving: git repack -Ad --write-bitmap-index
- If the only copy is corrupted, restore from backup or a healthy mirror. Consider setting up a regular mirror: git clone --mirror and periodic fetch.
Common scenarios and fixes
| Symptom | Likely cause | Fix |
|---|---|---|
| Error after power loss | Partial write | Quarantine bad pack, fetch, repack |
| Only shallow clone breaks | Missing history | git fetch --unshallow, repack |
| CI runners fail intermittently | Cache corruption | Clear VCS cache before job; fetch clean; repack |
| Submodule checkout fails | Submodule pack corrupt | Repair inside submodule path, then git submodule sync --recursive |
| Alternates file points to removed path | Broken alternates | Remove bad alternates entry; fetch; repack |
Pitfalls to avoid
- Do not delete .git/objects entirely; you can lose unpushed history.
- Do not run git gc --prune aggressively before refetching; you may drop objects you still need.
- Sync tools and antivirus can corrupt or lock pack files; exclude the .git directory from scanning and from cloud sync folders.
- Using git filter-repo or history rewrites during corruption can complicate recovery; repair first.
Performance notes
- Prefer git repack -Ad -l over git gc --aggressive on large repos; it’s faster and usually sufficient.
- On servers, write bitmaps for faster fetch/clone: git repack -Ad --write-bitmap-index.
- Use multi-pack index for many packs: git multi-pack-index write; git repack -Ad; git multi-pack-index expire.
- Enable built-in maintenance: git maintenance start to schedule background gc and incremental repacks.
- Keep repos off networked filesystems with poor locking; use local SSD where possible.
Prevention
- Ensure stable storage and power; use UPS on critical servers.
- Exclude .git from antivirus and file-sync tools.
- Regularly run git fsck in CI for critical repos and alert on failures.
- Maintain mirrors and backups; test recovery periodically.
Tiny FAQ
- Can I just reclone? Yes, if you have pushed all work and the remote is healthy. It’s the fastest fix.
- Which packs are safe to delete? Only the packs you verified as corrupt, and only after a successful refetch.
- Will git gc fix this by itself? Not if objects are unreadable. You must replace corrupted packs first, then gc/repack.
- Does this affect Git LFS? LFS has separate storage. Run git lfs fsck and git lfs fetch --all if LFS is used.
- What if the remote is also corrupted? Restore from a backup or a healthy mirror, or re-seed from developer clones that still have the history.