GitHub Actions Checkout Submodule Fails - Private Submodule Auth
A checkout with submodules fails on a private or cross-repo submodule because the default GITHUB_TOKEN cannot read it, or the submodule uses an SSH URL the runner has no key for.
What this error means
actions/checkout with submodules: true or recursive fails fetching a submodule with a 403 / authentication error, while the main repo checks out fine.
fatal: could not read Username for 'https://github.com': terminal prompts disabled
Error: fetching submodule libfoo failed
# or
git@github.com: Permission denied (publickey).Common causes
Default token cannot read the submodule repo
The built-in GITHUB_TOKEN is scoped to the current repository. A private submodule in another repo is not readable with it.
Submodule uses an SSH URL
A .gitmodules entry with a git@github.com: URL needs an SSH key on the runner; checkout cannot authenticate it with an HTTPS token.
How to fix it
Pass a token that can read the submodule
Use a PAT or GitHub App token with access to the submodule repositories so checkout can fetch them over HTTPS.
- uses: actions/checkout@v4
with:
submodules: recursive
token: ${{ secrets.SUBMODULE_PAT }}Use an SSH key or rewrite the URL
- Add an SSH deploy key with webfactory/ssh-agent and set submodules: recursive.
- Or convert SSH submodule URLs to HTTPS so the token-based auth applies.
- Confirm the .gitmodules paths and URLs are correct and reachable.
How to prevent it
- Provide a scoped PAT or App token for private submodules.
- Standardize submodule URLs on HTTPS for token auth in CI.
- Limit submodule fetch depth where full history is not needed.