How to fix ! [rejected] main -> main (stale info) error: failed to push some refs in Git
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- Fetch with prune to sync remote refs
- Verify the remote state
- Retry the force push with lease
- Set automatic pruning globally
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
- 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
- Git configuration fetch.prune is not set, so deleted remote branches persist locally
- You're working in a CI environment where caches contain stale refs
- 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"
The most common fix is to run git fetch with the --prune flag, which removes local references to remote branches that no longer exist:
git fetch --pruneThis 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.
Before force-pushing, inspect what commits exist on the remote that you might not have locally:
# See the difference between your local and remote
git log origin/main..HEAD
git log HEAD..origin/mainIf the second command shows commits, someone pushed changes you don't have. You should integrate those changes before force-pushing.
After fetching with prune, try your push again:
git push --force-with-lease origin mainIf the remote truly hasn't changed since your fetch, this should now succeed.
To prevent this issue in the future, configure Git to automatically prune stale refs on every fetch:
git config --global fetch.prune trueThis ensures your local remote-tracking branches always stay in sync with the actual remote state.
If you've confirmed that no one else has pushed changes and you still can't push, you can use regular --force:
git push --force origin mainWarning: 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:
# 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:
git push --force-with-lease=main:origin/main origin mainThis 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:
git remote prune originThis 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
- ๐Git Official Documentation
- ๐Git push --force-with-lease documentation(Official Docs)
- ๐ฌ
- ๐ฌ
- ๐ฌSafely force pushing with Git - whatsdoom.com(Stack Overflow)
- ๐ฌGit push force with lease - Today I Learned(Stack Overflow)