How to fix ! [rejected] main -> main (stale info) error: failed to push some refs in Git

GitINTERMEDIATEMEDIUMUpdated Oct 25, 2026ยท 286 views

This error occurs when using git push --force-with-lease and your local tracking branch has outdated information about the remote. The fix usually involves running git fetch --prune to sync your local refs with the actual remote state.

Quick fix

Fixes ! [rejected] main -> main (stale info) error: failed to push some refs

git fetch --prune
  1. Fetch with prune to sync remote refs
  2. Verify the remote state
  3. Retry the force push with lease
  4. Set automatic pruning globally
git โ€” error
git fetch --prune
! [rejected] main -> main (stale info) error: failed to push some refs

What this error means

The "rejected (stale info)" error is a safety mechanism built into Git's `--force-with-lease` option. When you use `git push --force-with-lease`, Git compares your local knowledge of the remote branch with its actual current state. If they don't match, Git refuses the push to prevent you from accidentally overwriting commits that you didn't know about. This error specifically means that your local repository's cached information about the remote branch (stored in `refs/remotes/origin/`) is out of date or "stale." The most common cause is that the remote branch was deleted and recreated, or someone else pushed changes that your local repo doesn't know about. The "stale info" variant is distinct from the standard "non-fast-forward" rejection. It indicates a mismatch between what your local Git thinks the remote looks like versus its actual state, rather than simply having divergent commit histories. This protection is especially important in collaborative workflows where force-pushing is sometimes necessary (like after rebasing), but you want to ensure you're not accidentally erasing a teammate's work.

Typical symptoms

  • git push --force-with-lease fails with 'rejected' and 'stale info' message
  • Error appears even when you believe your local branch is up to date
  • Standard git push works, but --force-with-lease does not
  • The error mentions 'failed to push some refs' after the rejection
  • Problem occurs after rebasing or amending commits
  • Issue appears in CI/CD pipelines using force-with-lease for deployments

Common causes

  1. The remote branch was deleted and recreated, but your local tracking ref still exists (most common)
  2. Another developer pushed to the branch after your last fetch, and you haven't synced
  3. Your local remote-tracking branch is out of sync due to a previous incomplete fetch
  4. Git configuration fetch.prune is not set, so deleted remote branches persist locally
  5. You're working in a CI environment where caches contain stale refs
  6. The remote repository was force-pushed by someone else, changing the branch history

How to fix "! [rejected] main -> main (stale info) error: failed to push some refs"

1Fetch with prune to sync remote refs

The most common fix is to run git fetch with the --prune flag, which removes local references to remote branches that no longer exist:

bash
git fetch --prune

This updates your local knowledge of the remote and removes any stale tracking branches. After this, your --force-with-lease should work if your local branch was actually up to date.

2Verify the remote state

Before force-pushing, inspect what commits exist on the remote that you might not have locally:

bash
# See the difference between your local and remote
git log origin/main..HEAD
git log HEAD..origin/main

If the second command shows commits, someone pushed changes you don't have. You should integrate those changes before force-pushing.

3Retry the force push with lease

After fetching with prune, try your push again:

bash
git push --force-with-lease origin main

If the remote truly hasn't changed since your fetch, this should now succeed.

4Set automatic pruning globally

To prevent this issue in the future, configure Git to automatically prune stale refs on every fetch:

bash
git config --global fetch.prune true

This ensures your local remote-tracking branches always stay in sync with the actual remote state.

5Use force as last resort

If you've confirmed that no one else has pushed changes and you still can't push, you can use regular --force:

bash
git push --force origin main

Warning: This bypasses the safety check. Only use this when you're certain you won't overwrite anyone else's work. In team environments, coordinate with your team before force-pushing.

Advanced notes

### Understanding --force-with-lease

The --force-with-lease flag was added to Git as a safer alternative to --force. It works by checking if your local remote-tracking ref matches the actual remote ref before allowing the push. Think of it as "force push, but only if the remote hasn't changed since I last looked."

The "lease" terminology comes from distributed systems: you're asking for a lease on the remote ref based on your last known state.

### The Fetch-Then-Push Caveat

Be aware that running git fetch immediately before git push --force-with-lease essentially makes it equivalent to git push --force. The safety mechanism relies on your potentially-outdated knowledge of the remote. If you always fetch first, you're always "up to date" from Git's perspective, even if you never actually looked at what was fetched.

### CI/CD Considerations

In CI/CD environments, this error commonly occurs when:

1. Cached Git repositories contain stale refs from previous runs
2. Shallow clones don't have complete ref information
3. Multiple pipeline runs race to push to the same branch

Solutions for CI:

bash
# Always prune before operations
git fetch --prune --unshallow || git fetch --prune

# Or use a fresh clone
git clone --depth 1 <repo>

### Specifying the Expected Ref

For more precise control, you can specify exactly what you expect the remote to look like:

bash
git push --force-with-lease=main:origin/main origin main

This explicitly states your expectation and will fail if the remote doesn't match, regardless of your local tracking branch state.

### Remote Prune Command

You can also manually prune without fetching:

bash
git remote prune origin

This removes stale remote-tracking branches without downloading new objects.

Frequently asked questions

What does "! [rejected] main -> main (stale info) error: failed to push some refs" mean?
The "rejected (stale info)" error is a safety mechanism built into Git's --force-with-lease option. When you use git push --force-with-lease, Git compares your local knowledge of the remote branch with its actual current state. If they don't match, Git refuses the push to prevent you from accidentally overwriting commits that you didn't know about.
How do I fix "! [rejected] main -> main (stale info) error: failed to push some refs"?
This error occurs when using git push --force-with-lease and your local tracking branch has outdated information about the remote. The fix usually involves running git fetch --prune to sync your local refs with the actual remote state.
What causes "! [rejected] main -> main (stale info) error: failed to push some refs"?
The remote branch was deleted and recreated, but your local tracking ref still exists (most common) Another developer pushed to the branch after your last fetch, and you haven't synced Your local remote-tracking branch is out of sync due to a previous incomplete fetch
Is the "! [rejected] main -> main (stale info) error: failed to push some refs" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading