This error occurs when Git cannot access a submodule's remote repository during clone, update, or init operations. Common causes include the repository being deleted, renamed, made private, or authentication issues preventing access. The fix involves verifying the repository exists, updating the submodule URL, or fixing authentication credentials.
The "fatal: repository not found" error for submodules indicates that Git cannot locate or access the remote repository specified in your project's submodule configuration. When you run `git submodule update --init`, `git clone --recurse-submodules`, or similar commands, Git attempts to fetch each submodule from its configured URL. This error typically means one of several things: - **The submodule repository no longer exists** - It may have been deleted or moved to a different location - **The repository was renamed** - GitHub and other hosts allow renaming, but old URLs may stop working after the redirect grace period - **Access permissions changed** - The repository may have been made private, or your access was revoked - **Authentication failure** - Your credentials may be invalid, expired, or not configured for this repository - **URL format issues** - The submodule URL may be malformed or use an unsupported protocol The submodule configuration is stored in two places: the `.gitmodules` file (committed to the repository) and your local `.git/config` file (local copy after `git submodule init`). Both must point to a valid, accessible repository.
First, confirm whether the submodule repository actually exists at the specified URL.
Check the submodule URL in your project:
# View all submodule URLs
cat .gitmodules
# Or use git config to see the URLs
git config --file .gitmodules --get-regexp urlTry accessing the repository directly:
- Open the URL in a web browser
- For private repositories, ensure you're logged in
- Check if the repository name matches exactly (case-sensitive on some hosts)
Test with git ls-remote:
# Replace with your actual submodule URL
git ls-remote https://github.com/user/submodule.git
# If using SSH
git ls-remote [email protected]:user/submodule.gitIf the repository doesn't exist, you'll need to find its new location or remove the submodule.
If the repository exists but is private, verify your authentication:
For HTTPS URLs:
# Check your credential helper
git config --global credential.helper
# On macOS, list stored credentials
git credential-osxkeychain get
# Test authentication with a simple clone
git clone https://github.com/user/submodule.git /tmp/test-cloneFor SSH URLs:
# Test SSH connection to GitHub
ssh -T [email protected]
# For GitLab
ssh -T [email protected]
# For Bitbucket
ssh -T [email protected]
# List loaded SSH keys
ssh-add -lIf SSH key is not loaded:
# Start ssh-agent
eval "$(ssh-agent -s)"
# Add your key
ssh-add ~/.ssh/id_rsa
# Or for newer ed25519 keys
ssh-add ~/.ssh/id_ed25519For GitHub Personal Access Tokens:
# Test with a PAT (replace YOUR_TOKEN)
git ls-remote https://[email protected]/user/submodule.gitIf the repository moved or you need to use a different URL format:
Update URL in .gitmodules:
# Edit .gitmodules directly, or use git config
git config --file .gitmodules submodule.path/to/submodule.url https://github.com/newuser/newrepo.git
# Verify the change
cat .gitmodulesSync the URL to your local config:
# This copies URLs from .gitmodules to .git/config
git submodule sync
# For all submodules including nested ones
git submodule sync --recursiveThen update the submodule:
git submodule update --init --recursiveIf switching from SSH to HTTPS (or vice versa):
# SSH format
git config --file .gitmodules submodule.mysubmodule.url [email protected]:user/repo.git
# HTTPS format
git config --file .gitmodules submodule.mysubmodule.url https://github.com/user/repo.git
# Sync and update
git submodule sync
git submodule update --initDon't forget to commit the .gitmodules change if you want others to use the new URL.
If the submodule state is corrupted, try a clean reinitialization:
Remove cached submodule data:
# Remove the submodule from .git/modules
rm -rf .git/modules/path/to/submodule
# Remove the submodule directory
rm -rf path/to/submodule
# Deinitialize the submodule
git submodule deinit -f path/to/submoduleReinitialize:
# Initialize and update
git submodule init path/to/submodule
git submodule update path/to/submodule
# Or do both in one command
git submodule update --init path/to/submoduleFor all submodules:
# Nuclear option - reset all submodules
git submodule deinit --all -f
rm -rf .git/modules/*
git submodule update --init --recursiveThis approach is useful when local submodule state doesn't match what's configured.
In CI/CD environments, authentication for private submodules requires special handling:
For GitHub Actions:
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.PAT_TOKEN }} # PAT with repo accessFor GitLab CI:
before_script:
- git config --global url."https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.com/".insteadOf "[email protected]:"
- git submodule sync --recursive
- git submodule update --init --recursiveFor CircleCI:
- checkout
- run:
name: Initialize submodules
command: |
git submodule sync
git submodule update --init --recursiveUsing deploy keys:
For private submodules, consider using deploy keys (read-only SSH keys) specific to each submodule repository.
Using .gitconfig URL rewriting:
# Rewrite SSH URLs to use HTTPS with token
git config --global url."https://oauth2:${TOKEN}@github.com/".insteadOf "[email protected]:"If the submodule repository is permanently unavailable, you may need to remove it:
Remove the submodule completely:
# 1. Deinitialize the submodule
git submodule deinit -f path/to/submodule
# 2. Remove from .git/modules
rm -rf .git/modules/path/to/submodule
# 3. Remove the submodule directory
git rm -f path/to/submodule
# 4. Commit the removal
git commit -m "Remove unavailable submodule"Replace with a fork or alternative:
# After removing, add a new submodule at the same path
git submodule add https://github.com/yourfork/repo.git path/to/submodule
# Or add an alternative library
git submodule add https://github.com/alternative/repo.git path/to/submodule
git commit -m "Replace submodule with fork/alternative"Convert submodule to regular files:
If you have a cached version of the submodule, you can convert it to regular tracked files:
# If the submodule directory has content
git rm --cached path/to/submodule
rm -rf path/to/submodule/.git
git add path/to/submodule
git commit -m "Convert submodule to regular directory"Understanding Submodule URL Resolution:
Git stores submodule information in two places:
1. .gitmodules - Committed file that all clones see
2. .git/config - Local file after running git submodule init
The git submodule sync command copies URLs from .gitmodules to .git/config. If someone updates .gitmodules and you pull their changes, your local .git/config won't automatically update - you need to run git submodule sync.
Relative Submodule URLs:
Git supports relative URLs for submodules:
# In .gitmodules
[submodule "lib"]
path = lib
url = ../other-repo.gitThis is resolved relative to the parent repository's remote URL. If your parent repo is at https://github.com/org/main.git, the submodule URL becomes https://github.com/org/other-repo.git.
Relative URLs can break when:
- The parent repo is cloned with a different protocol (SSH vs HTTPS)
- The repositories are on different hosts
- The directory structure doesn't match
Branch Tracking for Submodules:
By default, submodules are pinned to a specific commit. To track a branch:
# Configure submodule to track a branch
git config -f .gitmodules submodule.mysubmodule.branch main
# Update submodule to latest on that branch
git submodule update --remote mysubmoduleShallow Submodule Clones:
To speed up cloning, use shallow submodules:
git submodule update --init --depth 1This can fail if the pinned commit is too far back in history. In that case, you'll need a deeper clone.
Debugging Submodule Issues:
# Verbose output during submodule operations
GIT_TRACE=1 git submodule update --init
# Check submodule status
git submodule status
# Shows:
# - (minus) = Not initialized
# + (plus) = Checked out commit differs from index
# U = Has merge conflicts
# (space) = Properly initialized and up-to-dateHandling Nested Submodules:
Submodules can contain their own submodules. Always use --recursive:
git submodule update --init --recursive
git clone --recurse-submodules repo-urlSecurity Considerations:
- Be cautious with submodules from untrusted sources
- Submodules can execute code through hooks during clone/update
- Review submodule repositories before adding them to your project
- Consider using specific commit SHAs rather than branch tracking for better reproducibility and security
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: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git