How to fix error: Server does not allow request for unadvertised object in Git

GitINTERMEDIATEMEDIUMUpdated Dec 6, 2025ยท 248 views

This Git error occurs when trying to fetch a specific commit by its SHA hash, but the Git server is configured to only allow fetching advertised references like branches and tags. This commonly happens with submodules pointing to commits that don't exist on the remote or were removed during squash merges.

Quick fix

Fixes error: Server does not allow request for unadvertised object

# Sync submodule URLs from .gitmodules to .git/config
git submodule sync

# Update submodules recursively
git submodule update --init --recursive
  1. Sync submodule URLs and retry
  2. Use --force and --remote flags
  3. Push missing submodule commits
  4. Unshallow the repository
git โ€” error
# Sync submodule URLs from .gitmodules to .git/config
git submodule sync
# Update submodules recursively
git submodule update --init --recursive
error: Server does not allow request for unadvertised object

What this error means

The "Server does not allow request for unadvertised object" error indicates that Git is trying to fetch a specific commit by its SHA hash directly, but the remote server refuses this request. Git servers maintain a list of "advertised" references (branches and tags) that clients can fetch. By default, most Git servers including GitHub and GitLab do not allow fetching arbitrary commits by their hash - only commits reachable from advertised refs. This restriction exists for security and performance reasons. Allowing direct object fetches could expose commits that were force-pushed away or exist in private forks. The error most commonly occurs in these scenarios: 1. **Submodule commit not pushed**: You updated a submodule, pushed the parent repository, but forgot to push the submodule itself. The parent references a commit that doesn't exist on the submodule's remote. 2. **Squash merge removed the commit**: When a pull request is squash-merged, the original commits are replaced with a single squash commit. If a submodule referenced one of those original commits, that reference becomes invalid. 3. **Shallow clone limitations**: When cloning with `--depth`, only recent commits are fetched. Submodules referencing older commits will fail to fetch. 4. **Force push removed the commit**: If someone force-pushed to the submodule repository, commits may have been removed from the remote.

Typical symptoms

  • git submodule update --init fails with 'unadvertised object' error
  • git clone --recursive fails when initializing submodules
  • CI/CD pipeline fails during submodule checkout
  • Error includes a specific commit SHA that cannot be fetched
  • Fresh clone fails but existing clone works fine
  • Error occurs after merging a pull request with squash
  • Submodule works on author's machine but fails for others
  • Error appears after someone force-pushed to the submodule repository

Common causes

  1. Submodule commit was never pushed to the remote repository
  2. Pull request was squash-merged, removing the referenced commit
  3. Repository was cloned with --depth (shallow clone) missing older commits
  4. Submodule URL changed but .gitmodules wasn't synced
  5. Force push removed the referenced commit from the remote
  6. Git server has uploadpack.allowReachableSHA1InWant disabled (default)
  7. Submodule points to a commit in a private fork or deleted branch
  8. Using --shallow-submodules with commits not at branch tips

How to fix "error: Server does not allow request for unadvertised object"

1Sync submodule URLs and retry

The most common fix is to sync submodule URLs and update again. This resolves URL mismatches between .gitmodules and your local configuration:

bash
# Sync submodule URLs from .gitmodules to .git/config
git submodule sync

# Update submodules recursively
git submodule update --init --recursive

If this works, the issue was likely a stale submodule URL in your local configuration.

2Use --force and --remote flags

If syncing doesn't help, try forcing the update and using remote tracking branches instead of the specific commit:

bash
# Force update using remote branch instead of recorded commit
git submodule update --force --recursive --init --remote

Warning: The --remote flag updates submodules to the latest commit on their remote tracking branch, not the commit recorded in the parent repository. This may change which version of the submodule you're using. After verifying things work, you may want to commit the new submodule reference:

bash
git add .
git commit -m "Update submodule to latest"
3Push missing submodule commits

If you (or a teammate) updated the submodule but forgot to push it, the referenced commit won't exist on the remote. Navigate to the submodule and push:

bash
# Go to the submodule directory
cd path/to/submodule

# Check the current state
git status
git log --oneline -5

# Push the submodule
git push origin HEAD

# Return to parent repo
cd ..

# Now update should work
git submodule update --init --recursive

To prevent this in the future, use --recurse-submodules when pushing:

bash
# Check submodules before push (fails if unpushed)
git push --recurse-submodules=check

# Automatically push submodules first
git push --recurse-submodules=on-demand
4Unshallow the repository

If you're working with a shallow clone (common in CI/CD), fetch the full history:

bash
# Check if repository is shallow
git rev-parse --is-shallow-repository
# Returns "true" if shallow

# Fetch complete history
git fetch --unshallow

# Then update submodules
git submodule update --init --recursive

For CI/CD pipelines, configure full clones:

GitHub Actions:

yaml
- uses: actions/checkout@v4
  with:
    fetch-depth: 0  # Fetch all history
    submodules: recursive

GitLab CI:

yaml
variables:
  GIT_DEPTH: 0
  GIT_SUBMODULE_STRATEGY: recursive
5Check if the commit was squash-merged

If a pull request containing submodule updates was squash-merged, the original commit no longer exists. You need to update the submodule reference:

bash
# Go to the submodule
cd path/to/submodule

# Find a valid commit (check the default branch)
git fetch origin
git log origin/main --oneline -10

# Checkout a valid commit
git checkout origin/main

# Go back to parent and update the reference
cd ..
git add path/to/submodule
git commit -m "Update submodule to valid commit after squash merge"

To avoid this issue, configure your repository to use "merge commits" or "rebase and merge" instead of squash for PRs that update submodules.

6Remove and re-add the submodule

As a last resort, you can remove and re-add the submodule. Note: This loses any local submodule changes.

bash
# Remove the submodule
git submodule deinit -f path/to/submodule
rm -rf .git/modules/path/to/submodule
git rm -f path/to/submodule

# Re-add the submodule
git submodule add <repository-url> path/to/submodule

# Initialize and update
git submodule update --init --recursive

# Commit the change
git add .
git commit -m "Re-add submodule with valid reference"

This creates a fresh submodule reference pointing to the current HEAD of the submodule's default branch.

7Configure server to allow SHA fetching (self-hosted only)

If you control the Git server, you can enable fetching commits by SHA. This is NOT possible on GitHub or GitLab cloud.

For self-hosted Git servers, set these configuration options:

bash
# On the Git server, enable SHA fetching
git config uploadpack.allowReachableSHA1InWant true

# Or allow any SHA (less restrictive)
git config uploadpack.allowAnySHA1InWant true

# For hidden refs as well
git config uploadpack.allowTipSHA1InWant true

Security warning: Enabling these options can expose commits that were intentionally hidden (force-pushed away, or in private forks). Only enable on private servers where this is acceptable.

Advanced notes

### Understanding Advertised vs Unadvertised Objects

When you run git fetch, the server first sends a list of "advertised" references - branches and tags that the client is allowed to fetch. The client then requests objects reachable from these refs.

By default, Git servers only allow fetching objects reachable from advertised refs. This prevents:
- Fetching commits from private forks
- Accessing commits that were force-pushed away
- Retrieving objects that exist in the server's object store but aren't meant to be public

Submodules break this model because they record specific commit SHAs, not branch names. When that commit isn't at a branch tip, it becomes "unadvertised."

### Server Configuration Options

Three server-side options control SHA fetching:

| Option | Allows |
|--------|--------|
| uploadpack.allowTipSHA1InWant | Fetching SHAs at branch/tag tips |
| uploadpack.allowReachableSHA1InWant | Fetching any SHA reachable from a ref |
| uploadpack.allowAnySHA1InWant | Fetching any SHA in the object store |

GitHub and GitLab have allowReachableSHA1InWant enabled, but only for commits reachable from branches you have access to.

### Git Version Considerations

This error's behavior changed across Git versions:

- Git 2.5+: Added allowReachableSHA1InWant protocol support
- Git 2.11+: Improved shallow clone handling
- Git 2.22+: Some users reported new occurrences of this error due to protocol changes

If downgrading Git temporarily fixes the issue, it may indicate a protocol negotiation problem rather than a missing commit.

### Preventing This Error

1. Always push submodules first:

bash
git push --recurse-submodules=on-demand

2. Use branch tracking for submodules (Git 2.8+):

bash
git config -f .gitmodules submodule.path.branch main
   git submodule update --remote

3. Avoid squash merges for submodule updates: Squashing removes the commits that submodules reference.

4. Document submodule workflow: Ensure all contributors know to push submodules before the parent repo.

### CI/CD Best Practices

For reliable submodule handling in CI/CD:

yaml
# GitHub Actions
- uses: actions/checkout@v4
  with:
    fetch-depth: 0
    submodules: recursive

# If submodules still fail, add explicit sync
- run: |
    git submodule sync --recursive
    git submodule update --init --recursive --force

### Diagnosing the Problem

To find which submodule and commit is causing the issue:

bash
# Show submodule status
git submodule status --recursive

# Check what commit is expected
cat .gitmodules
git ls-tree HEAD path/to/submodule

# Verify if commit exists on remote
cd path/to/submodule
git fetch origin
git cat-file -t <commit-sha>  # Should output "commit"
git branch -r --contains <commit-sha>  # Should list branches

If git branch -r --contains returns nothing, the commit exists locally but isn't reachable from any remote branch.

Frequently asked questions

What does "error: Server does not allow request for unadvertised object" mean?
The "Server does not allow request for unadvertised object" error indicates that Git is trying to fetch a specific commit by its SHA hash directly, but the remote server refuses this request. Git servers maintain a list of "advertised" references (branches and tags) that clients can fetch. By default, most Git servers including GitHub and GitLab do not allow fetching arbitrary commits by their hash - only commits reachable from advertised refs.
How do I fix "error: Server does not allow request for unadvertised object"?
This Git error occurs when trying to fetch a specific commit by its SHA hash, but the Git server is configured to only allow fetching advertised references like branches and tags. This commonly happens with submodules pointing to commits that don't exist on the remote or were removed during squash merges.
What causes "error: Server does not allow request for unadvertised object"?
Submodule commit was never pushed to the remote repository Pull request was squash-merged, removing the referenced commit Repository was cloned with --depth (shallow clone) missing older commits
Is the "error: Server does not allow request for unadvertised object" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading