Git "Permission denied (publickey)" in CI - Fix SSH Auth
By Daniel Zoghalchali·Latchkey
The SSH server rejected every key the client offered. In CI this almost always means no private key is loaded on the runner, or the key that is loaded was never added to the Git host or granted access to the repo.
What this error means
An SSH clone/fetch fails with git@github.com: Permission denied (publickey) and then fatal: Could not read from remote repository. It is deterministic - the same key fails the same way on every run.
git clone output
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.
Please make sure you have the correct access rights
and the repository exists.
Diagnose it: depth, refs, or credentials?
Terminal
git rev-parse --is-shallow-repository
git rev-parse --abbrev-ref HEAD # prints HEAD when detached
git log --oneline -3
git remote -v
Common causes
No private key loaded on the runner
The runner has no SSH key in its agent or ~/.ssh, so the client offers nothing and the server falls back to "publickey" denial.
The key is not registered with the host or repo
A key exists but was never added as a deploy key on the repo or an SSH key on the account/org, so the host does not recognize it.
Wrong key permissions or no agent
A private key with loose permissions is ignored by SSH, and without a running ssh-agent the key is never offered at all.
How to fix it
Load the deploy/SSH key on GitHub Actions
Use the checkout action’s ssh-key input, or a dedicated action, to load a private key that has access to the repo.
.github/workflows/ci.yml
- uses:actions/checkout@v4with:ssh-key:${{ secrets.DEPLOY_KEY }} # private key; add the public half as a repo deploy key
Set up the agent and key manually
If you manage SSH yourself, start the agent, add the key with correct permissions, and trust the host.
Add the public key as a repo deploy key (or an account/org SSH key) with the right access.
Verify with ssh -vT git@github.com and check which key is offered.
Make sure the private key file is mode 600 and owned by the runner user.
How to prevent it
Use the checkout action’s ssh-key input instead of hand-rolling SSH.
Scope deploy keys per repo with the minimum access required.
Store the private key as a secret and never bake it into the image.
Frequently asked questions
What causes Git "Permission denied (publickey)" in CI?
There are 3 common causes: no private key loaded on the runner, the key is not registered with the host or repo, and wrong key permissions or no agent. The runner has no SSH key in its agent or ~/.ssh, so the client offers nothing and the server falls back to "publickey" denial.
How do I fix Git "Permission denied (publickey)" in CI?
There are 3 fixes depending on which cause you have: load the deploy/ssh key on github actions, set up the agent and key manually, and confirm the key is authorized. Work through them in order, since the first is the most common.
What does Git "Permission denied (publickey)" in CI actually mean?
An SSH clone/fetch fails with git@github.com: Permission denied (publickey) and then fatal: Could not read from remote repository.
How do I stop Git "Permission denied (publickey)" in CI happening again?
Use the checkout action’s ssh-key input instead of hand-rolling SSH. The prevention section lists 3 changes that keep it from recurring.