How to fix fatal: unable to read tree object in treeless clone in Git

GitINTERMEDIATEMEDIUMUpdated Dec 6, 2025· 301 views

This error occurs when Git cannot read a required tree object in a partial clone created with --filter=tree:0. Treeless clones only download commit objects initially, fetching trees on demand. The fix typically involves converting to a full clone, using a blobless clone instead, or ensuring network connectivity to fetch missing objects.

Quick fix

Fixes fatal: unable to read tree object in treeless clone

# Check the remote URL
git remote -v

# Test connectivity to the remote
git ls-remote origin

# Try to fetch explicitly
git fetch origin
  1. Verify network connectivity to the remote
  2. Convert treeless clone to full clone
  3. Use blobless clone instead of treeless
  4. Fix submodule-related tree fetch issues
git — error
# Check the remote URL
git remote -v
# Test connectivity to the remote
git ls-remote origin
# Try to fetch explicitly
git fetch origin
fatal: unable to read tree object in treeless clone

What this error means

The "fatal: unable to read tree object in treeless clone" error indicates that Git needs to access a tree object that wasn't downloaded during the initial partial clone operation, and it cannot fetch it from the remote repository. When you create a treeless clone using `git clone --filter=tree:0`, Git downloads only commit objects initially. Tree objects (which represent directory structures) and blob objects (file contents) are fetched on demand when needed. This makes the initial clone extremely fast, especially for large repositories. This error typically occurs when: - **Network connectivity issues** - Git cannot reach the remote server to fetch the missing tree object - **Remote repository changes** - The tree object no longer exists on the remote (force push, rebase, or garbage collection) - **Corrupted partial clone state** - The local repository's "promisor" configuration is misconfigured - **Server doesn't support partial clone** - The remote Git server may have disabled the feature or doesn't support fetching individual objects - **Operations requiring full history** - Commands like `git log -- <path>` trigger massive tree downloads in treeless clones Treeless clones are designed for CI/CD build environments where you clone, build, and discard. They are not recommended for regular development work due to these limitations.

Typical symptoms

  • Clone completes but checkout fails with 'fatal: unable to read tree object'
  • git checkout or git switch fails in a repository cloned with --filter=tree:0
  • CI/CD pipeline fails during checkout step after a treeless clone
  • git log -- <path> triggers the error or causes extremely slow operation
  • git blame or git diff operations fail with tree object errors
  • Error message includes 'warning: Clone succeeded, but checkout failed'
  • Repository shows incomplete checkout with missing files
  • git status shows files as deleted that should exist

Common causes

  1. Network connectivity prevents fetching missing tree objects from remote
  2. The remote repository was force-pushed and the referenced tree no longer exists
  3. Git server does not support partial clone object fetching
  4. The repository was garbage collected on the server, removing unreferenced trees
  5. Firewall or proxy blocking Git's object fetch requests
  6. Using --mirror flag with --filter=tree:0 which is incompatible
  7. The remote.origin.promisor configuration is missing or incorrect
  8. Repository submodules triggering excessive tree fetches during git fetch
  9. Attempting operations that require full tree history in a treeless clone
  10. Server-side partial clone support was disabled after the initial clone

How to fix "fatal: unable to read tree object in treeless clone"

1Verify network connectivity to the remote

First, confirm you can reach the remote repository and fetch objects:

Test basic connectivity:

bash
# Check the remote URL
git remote -v

# Test connectivity to the remote
git ls-remote origin

# Try to fetch explicitly
git fetch origin

If behind a proxy or firewall:

bash
# Check proxy settings
git config --global --get http.proxy
git config --global --get https.proxy

# Test with verbose output
GIT_TRACE=1 GIT_CURL_VERBOSE=1 git fetch origin

If network connectivity is the issue, resolve firewall/proxy problems before proceeding.

2Convert treeless clone to full clone

The most reliable fix is to convert your partial clone to a full clone by fetching all missing objects:

Remove the filter and fetch all objects:

bash
# Check current partial clone configuration
git config --get remote.origin.partialclonefilter

# Remove the filter setting
git config --unset remote.origin.partialclonefilter

# Fetch all objects with --refetch
git fetch --refetch

# Remove the promisor marking (indicates objects may be missing)
git config --unset remote.origin.promisor

# Verify the conversion
git fsck

Alternative: Fresh full clone:

bash
# If the above doesn't work, do a fresh clone
cd ..
mv my-repo my-repo-backup
git clone https://github.com/user/repo.git my-repo
cd my-repo

# Copy any local changes from backup if needed

After conversion, all Git operations should work normally.

3Use blobless clone instead of treeless

Blobless clones (--filter=blob:none) are more practical than treeless clones for most use cases:

Clone with blobless filter:

bash
# Blobless clone - downloads all commits and trees, but not file contents
git clone --filter=blob:none https://github.com/user/repo.git

# This is better because:
# - git log -- <path> works without downloading extra objects
# - Only file contents (blobs) are fetched on demand
# - Much more compatible with normal Git workflows

Convert existing treeless to blobless:

bash
# Unfortunately, you cannot directly convert between filter types
# You need to re-clone with the blobless filter

cd ..
git clone --filter=blob:none https://github.com/user/repo.git my-repo-new

When to use each type:
| Clone Type | Best For |
|------------|----------|
| Full clone | Daily development, all features work |
| Blobless | Large repos with big files, good for development |
| Treeless | CI builds that only need the latest code, then discard |
| Shallow | Only need recent commits, no history required |

4Fix submodule-related tree fetch issues

Repositories with submodules can cause excessive tree fetching in treeless clones:

Disable submodule recursion for treeless clones:

bash
# Prevent fetch from downloading trees for submodule changes
git config fetch.recurseSubmodules false

# Now fetch won't trigger tree downloads for submodule detection
git fetch origin

Clone without submodule recursion:

bash
# When initially cloning, don't recurse into submodules
git clone --filter=tree:0 --no-recurse-submodules https://github.com/user/repo.git

# Initialize submodules separately if needed
git submodule update --init --depth 1

For CI/CD with submodules:

yaml
# GitHub Actions example
- uses: actions/checkout@v4
  with:
    filter: blob:none  # Use blobless, not treeless
    submodules: false  # Handle submodules separately

This prevents the submodule detection logic from triggering tree downloads for every commit.

5Handle CI/CD treeless clone failures

In CI/CD environments, treeless clone errors usually indicate the build configuration needs adjustment:

GitHub Actions - use fetch-depth or filter correctly:

yaml
- uses: actions/checkout@v4
  with:
    # Option 1: Shallow clone (usually sufficient for builds)
    fetch-depth: 1

    # Option 2: Blobless clone (if you need history)
    # filter: blob:none

GitLab CI:

yaml
variables:
  # Use shallow clone instead of treeless
  GIT_DEPTH: 1
  # Or for blobless:
  # GIT_STRATEGY: clone
  # GIT_CLONE_PATH: $CI_BUILDS_DIR/$CI_PROJECT_PATH

script:
  - git clone --filter=blob:none --depth 1 $CI_REPOSITORY_URL .

CircleCI:

yaml
- checkout:
    # CircleCI doesn't support treeless clones well
    # Use shallow clone instead
    depth: 1

Jenkins:

groovy
checkout([
    $class: 'GitSCM',
    branches: [[name: '*/main']],
    extensions: [[$class: 'CloneOption', shallow: true, depth: 1]],
    userRemoteConfigs: [[url: 'https://github.com/user/repo.git']]
])

Key recommendation: For CI/CD, prefer shallow clones (--depth 1) or blobless clones over treeless clones.

6Recover from corrupted partial clone state

If the partial clone state is corrupted, you may need to repair or recreate it:

Check repository integrity:

bash
# Run fsck to identify issues
git fsck --full

# Check promisor remote configuration
git config --get remote.origin.promisor
git config --get remote.origin.partialclonefilter

Reset promisor configuration:

bash
# If promisor is incorrectly set
git config remote.origin.promisor true
git config remote.origin.partialclonefilter tree:0

# Try fetching again
git fetch origin

Force re-fetch of missing objects:

bash
# Attempt to fetch the specific missing tree (if you know the hash)
git fetch-pack --thin origin <tree-hash>

# Or fetch everything from the remote
git fetch --all --prune

Last resort - fresh clone:

bash
# Backup any local work
git stash
git format-patch origin/main --stdout > my-changes.patch

# Fresh clone
cd ..
rm -rf my-repo
git clone https://github.com/user/repo.git my-repo

# Apply saved changes
cd my-repo
git apply ../my-repo-backup/my-changes.patch

Advanced notes

Understanding Partial Clone Types:

Git supports several partial clone filters, each with different trade-offs:

| Filter | Command | Downloads Initially | Fetches On Demand |
|--------|---------|---------------------|-------------------|
| Full | git clone | Everything | Nothing |
| Blobless | --filter=blob:none | Commits + Trees | Blobs (file contents) |
| Treeless | --filter=tree:0 | Commits only | Trees + Blobs |
| Shallow | --depth N | Last N commits + all objects | Nothing |

Why Treeless Clones Are Problematic:

Treeless clones save the most bandwidth initially, but many Git operations require tree objects:
- git log -- <path> needs trees to track file history
- git blame needs trees to find file locations
- git checkout <branch> needs the tree for that commit
- git diff between commits needs both trees

Each of these operations triggers network requests to fetch trees, which can be slow and may fail if the server is unavailable.

Server Requirements:

Partial clone requires Git 2.22+ on both client and server. Not all Git hosting services fully support treeless clones:

- GitHub: Full support for partial clones
- GitLab: Supported since GitLab 12.4
- Bitbucket: Limited support
- Azure DevOps: Supported (announced 2022)

Promisor Remotes:

When you create a partial clone, Git marks the remote as a "promisor remote" - meaning it promises to provide missing objects on demand:

bash
# Check promisor configuration
git config --get remote.origin.promisor  # Should be "true"
git config --get remote.origin.partialclonefilter  # Shows the filter type

Garbage Collection Considerations:

In a partial clone, Git cannot garbage collect objects it never had. However, if you convert to a full clone and then run git gc, Git will properly manage all objects.

Mirror Clones Incompatibility:

The --mirror flag is incompatible with --filter=tree:0. This combination causes the "Clone succeeded, but checkout failed" error because mirror clones expect all refs to be present, but treeless clones defer object fetching.

Fetching in Treeless Clones:

When running git fetch in a treeless clone with submodules, Git's submodule change detection can trigger tree downloads for every new commit. Disable this with:

bash
git config fetch.recurseSubmodules false

Performance Comparison:

For a large monorepo (e.g., 10GB full clone):
- Full clone: ~10GB download, 5+ minutes
- Blobless clone: ~500MB download, 30 seconds
- Treeless clone: ~50MB download, 5 seconds
- Shallow clone (depth 1): ~100MB download, 10 seconds

However, treeless clones will download trees on demand, potentially exceeding blobless clone sizes over time if you browse history.

Frequently asked questions

What does "fatal: unable to read tree object in treeless clone" mean?
The "fatal: unable to read tree object in treeless clone" error indicates that Git needs to access a tree object that wasn't downloaded during the initial partial clone operation, and it cannot fetch it from the remote repository. When you create a treeless clone using git clone --filter=tree:0, Git downloads only commit objects initially. Tree objects (which represent directory structures) and blob objects (file contents) are fetched on demand when needed.
How do I fix "fatal: unable to read tree object in treeless clone"?
This error occurs when Git cannot read a required tree object in a partial clone created with --filter=tree:0. Treeless clones only download commit objects initially, fetching trees on demand. The fix typically involves converting to a full clone, using a blobless clone instead, or ensuring network connectivity to fetch missing objects.
What causes "fatal: unable to read tree object in treeless clone"?
Network connectivity prevents fetching missing tree objects from remote The remote repository was force-pushed and the referenced tree no longer exists Git server does not support partial clone object fetching
Is the "fatal: unable to read tree object in treeless clone" error serious?
It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.

Official resources & further reading