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.
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.
First, confirm you can reach the remote repository and fetch objects:
Test basic connectivity:
# Check the remote URL
git remote -v
# Test connectivity to the remote
git ls-remote origin
# Try to fetch explicitly
git fetch originIf behind a proxy or firewall:
# 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 originIf network connectivity is the issue, resolve firewall/proxy problems before proceeding.
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:
# 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 fsckAlternative: Fresh full clone:
# 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 neededAfter conversion, all Git operations should work normally.
Blobless clones (--filter=blob:none) are more practical than treeless clones for most use cases:
Clone with blobless filter:
# 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 workflowsConvert existing treeless to blobless:
# 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-newWhen 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 |
Repositories with submodules can cause excessive tree fetching in treeless clones:
Disable submodule recursion for treeless clones:
# 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 originClone without submodule recursion:
# 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 1For CI/CD with submodules:
# GitHub Actions example
- uses: actions/checkout@v4
with:
filter: blob:none # Use blobless, not treeless
submodules: false # Handle submodules separatelyThis prevents the submodule detection logic from triggering tree downloads for every commit.
In CI/CD environments, treeless clone errors usually indicate the build configuration needs adjustment:
GitHub Actions - use fetch-depth or filter correctly:
- 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:noneGitLab CI:
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:
- checkout:
# CircleCI doesn't support treeless clones well
# Use shallow clone instead
depth: 1Jenkins:
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.
If the partial clone state is corrupted, you may need to repair or recreate it:
Check repository integrity:
# Run fsck to identify issues
git fsck --full
# Check promisor remote configuration
git config --get remote.origin.promisor
git config --get remote.origin.partialclonefilterReset promisor configuration:
# If promisor is incorrectly set
git config remote.origin.promisor true
git config remote.origin.partialclonefilter tree:0
# Try fetching again
git fetch originForce re-fetch of missing objects:
# 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 --pruneLast resort - fresh clone:
# 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.patchUnderstanding 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:
# Check promisor configuration
git config --get remote.origin.promisor # Should be "true"
git config --get remote.origin.partialclonefilter # Shows the filter typeGarbage 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:
git config fetch.recurseSubmodules falsePerformance 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.
kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: missing blob object 'abc1234' in blobless clone
How to fix 'missing blob object in blobless clone' in Git