Skip to content

Fix: Git fatal: not a valid object name: 'main'

FixDevs · (Updated: )

Part of:  Docker, DevOps & Infrastructure

Quick Answer

How to fix Git fatal not a valid object name error caused by empty repositories, wrong branch names, missing initial commits, and corrupted refs.

The Error

You run a Git command and get:

fatal: not a valid object name: 'main'

Or variations:

fatal: not a valid object name: 'master'
fatal: not a valid object name: 'HEAD'
fatal: not a valid object name: 'origin/main'
error: pathspec 'main' did not match any file(s) known to git

Git cannot find the branch, commit, or ref you specified. The name does not point to any existing Git object.

Why This Happens

Git’s data model is a directed acyclic graph of immutable objects (blobs, trees, commits, tags) addressed by SHA-1 (or SHA-256 in newer repos). A branch name like main is not an object — it is a ref, a file under .git/refs/heads/ that contains the hash of a commit. When Git is asked to resolve main, it reads .git/refs/heads/main, finds the hash, and looks up the commit. If the ref file does not exist, or the file is empty, or the file contains a hash for a commit that has been garbage-collected, Git emits “not a valid object name.”

The same error message is used for several distinct situations: a fresh git init (no refs exist yet), a clone where the named branch lives only on the remote and has not been fetched, a corrupted ref, and a typo. Reading the message literally — “Git could not find an object with this name” — is more useful than reading it as “the branch is missing,” because the resolution path is different for each case.

There is also a packed-refs subtlety. When Git runs git gc it consolidates loose refs into .git/packed-refs. If a process holds a stale reference to .git/refs/heads/main while packing happens, you can end up with the loose file empty and the packed entry present but pointing at a pruned object. The result is the same error even though the branch “appears” to exist in git branch output.

Common causes:

  • Empty repository. You just ran git init but have not made any commits yet. No branches exist until the first commit.
  • Wrong branch name. You typed main but the branch is called master, or vice versa.
  • Remote branch not fetched. You reference origin/main but have not run git fetch yet.
  • Typo in the branch name. git checkout featur/login instead of feature/login.
  • Deleted branch. The branch was deleted locally or on the remote.
  • Corrupted repository. The .git directory has missing or corrupted objects.

Platform and Environment Differences

This error frequently shows up in CI before it shows up locally, because CI environments deliberately fetch less of the repository to save time. Understanding the differences between checkout strategies and filesystems is the fastest way to stop chasing it.

CI runners default to shallow clones. GitHub Actions’ actions/checkout uses fetch-depth: 1 by default, which downloads only the tip commit of the triggering ref. Any reference to another branch, tag, or older commit fails with “not a valid object name” because that object was never fetched. Set fetch-depth: 0 to clone the full history when you need to merge, rebase, diff against main, or read tags. The same applies to GitLab CI’s GIT_DEPTH and CircleCI’s --depth flag.

Linux is case-sensitive, macOS APFS and Windows NTFS are usually not. A branch called Feature/Login on Linux is distinct from feature/login, and git fetch happily creates both .git/refs/heads/Feature/Login and .git/refs/heads/feature/login. On macOS HFS+/APFS or Windows NTFS, the second one overwrites the first because the filesystem treats them as the same path, but Git’s packed-refs may still list both. The result is that one of the two becomes unresolvable. Avoid mixed-case branch names entirely, or set core.ignorecase=false if you control the filesystem.

git worktree writes per-worktree state files under .git/worktrees/<name>/. The HEAD file in each worktree is independent of the main one. If you cloned the worktree directory but did not copy .git/worktrees, or you copied the project between machines using a tool that skips dotfiles, the worktree HEAD ends up pointing at refs that do not exist. Running git worktree repair recreates the linkage; git worktree prune removes stale entries.

Submodules in CI are a common source. The parent repo pins each submodule to a specific commit, but git submodule update --init only initializes submodules listed in .gitmodules. If a submodule was renamed or removed, the pinned commit no longer corresponds to anything fetchable, and any pathspec referencing it fails. Run git submodule sync after pulling parent changes that move submodules.

git gc reflog truncation. The reflog (where you find old commit hashes to recover lost branches) is pruned by git gc after 90 days by default (gc.reflogExpire) and unreachable entries after 30 days (gc.reflogExpireUnreachable). If you delete a branch and then try to recover it from the reflog months later, the entries may already be gone, and git fsck --lost-found will not help once the objects themselves are pruned.

Bare repositories (used on servers) have no working directory, and many commands behave differently. git checkout fails immediately, HEAD points to a symbolic ref rather than a commit, and git rev-parse HEAD resolves only after at least one push. If the server was created with git init --bare and never received a push, every ref query returns “not a valid object name.”

Fix 1: Make an Initial Commit

The most common cause. A freshly initialized repository has no commits and no branches:

git init
git branch  # Shows nothing — no branches exist yet

Fix: Create the first commit:

git add .
git commit -m "Initial commit"

After this, the default branch (main or master) is created. Now git branch shows the branch name.

If you want the branch named main:

git init
git add .
git commit -m "Initial commit"
git branch -M main

Pro Tip: Configure Git to use main as the default branch name for all new repositories:

git config --global init.defaultBranch main

This avoids the main vs master confusion for future projects.

Fix 2: Check the Correct Branch Name

You might be using the wrong branch name. Check what branches exist:

# Local branches
git branch

# Remote branches
git branch -r

# All branches
git branch -a

If the output shows master but you typed main:

git checkout master

Or rename the branch:

git branch -M master main

Check the default branch on the remote:

git remote show origin

Look for the HEAD branch: line — that is the remote’s default branch.

Fix 3: Fetch Remote Branches

If the error mentions a remote branch like origin/main:

git fetch origin

This downloads all remote branches and refs. After fetching:

git checkout main  # Now works if origin/main exists

If the remote repository is empty (no commits), git fetch has nothing to download and origin/main does not exist.

Clone instead of init + remote add:

If you are setting up from an existing remote repository:

git clone https://github.com/user/repo.git
cd repo
git branch  # Shows the default branch

Cloning fetches all branches automatically.

Fix 4: Fix git checkout or git switch Errors

When checking out a branch that does not exist locally but exists on the remote:

# This fails if the branch doesn't exist locally:
git checkout feature/login
# error: pathspec 'feature/login' did not match any file(s) known to git

# Fix — fetch first:
git fetch origin
git checkout feature/login  # Auto-creates local tracking branch

Or use git switch (Git 2.23+):

git fetch origin
git switch feature/login

Create a new branch:

git checkout -b feature/login
# or
git switch -c feature/login

The -b (or -c) flag creates the branch if it does not exist.

Fix 5: Fix git merge and git rebase Errors

When merging or rebasing, the target branch must exist:

git merge main
# fatal: not a valid object name: 'main'

Check available branches:

git branch -a

If the branch exists on the remote but not locally:

git fetch origin
git merge origin/main

Or create a local tracking branch first:

git checkout main
git checkout -  # Go back to previous branch
git merge main

For merge conflicts after successful merging, see Fix: git merge conflict.

Fix 6: Fix git log on Empty Repository

Running git log on a repository with no commits:

git init
git log
# fatal: your current branch 'main' does not have any commits yet

This is expected. There is nothing to show. Make a commit first (Fix 1).

git show also fails:

git show HEAD
# fatal: not a valid object name: 'HEAD'

HEAD does not exist until the first commit. After committing, HEAD points to the latest commit.

Fix 7: Fix Orphan Branch Issues

An orphan branch has no parent commit — it starts a completely new history:

git checkout --orphan new-branch
git log  # fatal: your current branch 'new-branch' does not have any commits yet

Fix: Commit on the orphan branch:

git checkout --orphan new-branch
git add .
git commit -m "Initial commit on new branch"

If you created an orphan branch accidentally and want to go back:

git checkout main

If this fails with a detached HEAD error, see Fix: git detached HEAD.

Common Mistake: Using git checkout --orphan thinking it creates a regular branch. Orphan branches are used for special purposes like gh-pages or starting a completely separate history. For a normal new branch, use git checkout -b branch-name.

Fix 8: Fix Corrupted Refs

If the branch existed previously and the error appeared suddenly, the ref might be corrupted:

Check the ref file:

cat .git/refs/heads/main

If the file is empty or contains garbage, the ref is corrupted.

Fix from the reflog:

git reflog

Find the last valid commit hash for the branch and recreate the ref:

git branch -f main abc1234

Fix from the remote:

git fetch origin
git branch -f main origin/main

Run git fsck to check for corruption:

git fsck --full

This checks all objects in the repository for consistency. If it reports errors, the repository might need repair from a fresh clone.

For similar Git reference issues, see Fix: git cannot lock ref.

Still Not Working?

If none of the fixes above resolved the error:

Check for case sensitivity. On Linux, Main and main are different branch names. On macOS and Windows, they are the same but Git can still get confused:

git branch -a | grep -i main

Check for special characters. Branch names with spaces, tildes, or colons are problematic. Rename the branch to use only alphanumeric characters, hyphens, and forward slashes.

Check bare repositories. If you are working in a bare repository (used as a server), there is no working directory and some commands behave differently. Check with git rev-parse --is-bare-repository.

Check submodules. If the error occurs inside a submodule, the submodule might be at a detached HEAD or an uninitialized state:

git submodule update --init --recursive

Try a fresh clone. If the local repository is corrupted beyond repair:

cd ..
mv myproject myproject-backup
git clone https://github.com/user/repo.git myproject

Then copy any uncommitted work from the backup.

Check fetch-depth in your CI workflow. A shallow clone (fetch-depth: 1 on GitHub Actions, the default) does not download other branches or tags. Commands like git merge-base origin/main HEAD, git describe, and git log main..HEAD all fail with “not a valid object name.” Set fetch-depth: 0 for jobs that need history, or fetch what you need explicitly with git fetch --depth=50 origin main.

Check git worktree linkage. If you copied or moved a worktree, the per-worktree files under .git/worktrees/<name>/ may point at the wrong main repo. Run git worktree list to see registered worktrees and git worktree repair to fix the link. If the worktree was deleted on disk but Git still tracks it, git worktree prune cleans up the stale entry.

Check the packed-refs file for stale entries. After a git gc, refs live in .git/packed-refs. If a packed entry points at a pruned commit, the branch name resolves to nothing. Inspect with cat .git/packed-refs and force-update with git fetch origin <branch>:<branch> to overwrite the bad entry from the remote.

If the error is specifically about the repository not being recognized as a Git repo at all, see Fix: fatal: not a git repository.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles