Troubleshooting “gpg failed to sign the data” Jump to heading
error: gpg failed to sign the data
fatal: failed to write commit object That message is Git reporting that the signing program exited non-zero. It says nothing about why, because Git does not know. The real error is printed by gpg (or ssh-keygen) and is usually swallowed. There are perhaps eight common causes, and guessing between them wastes an afternoon. This page gives a fixed diagnostic order: make the real error visible first, then check each cause from most to least likely. It sits within the GPG vs SSH commit signing topic, and most of it applies to SSH signing too.
When to use this approach Jump to heading
git commitfails with “gpg failed to sign the data” or “failed to write commit object”.- Signing worked yesterday and stopped without any configuration change.
- Signing works in a terminal but fails in an editor, a GUI client, or a hook.
- Signing fails only in CI or a container — in that case also see signing commits inside ephemeral containers.
Step 1 — Make the real error visible Jump to heading
Run the signing program the way Git does, outside Git. That prints the error Git hides.
# What Git will call, and with which key
git config --get gpg.program || echo gpg
git config --get user.signingKey
# Sign something by hand with the same key
echo test | gpg --clearsign --local-user "$(git config user.signingKey)" For more detail from Git itself, trace the call:
GIT_TRACE=1 git commit --allow-empty -m "trace" 2>&1 | grep -iE 'gpg|run_command' The trace shows the exact command line Git runs. Copy it and run it by hand; whatever it prints is the real diagnosis.
Step 2 — Fix the terminal: GPG_TTY and pinentry Jump to heading
The most frequent cause on Linux and macOS. The agent needs to show a passphrase prompt and does not know which terminal to use.
export GPG_TTY=$(tty)
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc # or ~/.zshrc
gpg-connect-agent updatestartuptty /bye In editors and GUI clients there is no terminal at all, so a terminal pinentry cannot work. Configure a graphical one.
# ~/.gnupg/gpg-agent.conf — pick the one installed on your system
pinentry-program /usr/bin/pinentry-gnome3
# macOS with pinentry-mac:
# pinentry-program /opt/homebrew/bin/pinentry-mac gpgconf --kill gpg-agent # agent restarts on next use with the new setting
echo test | gpg --clearsign >/dev/null && echo "signing ok" Step 3 — Check the key ID and that it can sign Jump to heading
A key ID that does not exist, or names a key without the sign capability, fails immediately. So does a key whose secret part is not on this machine — common after following keeping a GPG primary key offline and pointing Git at the primary instead of the subkey.
gpg --list-secret-keys --keyid-format long
# sec# ed25519/0xA1B2... [C] <- primary, secret absent (#)
# ssb ed25519/0x1122... [S] [expires…] <- signing subkey, present
git config --global user.signingKey 0x1122334455667788! # the [S] subkey, with ! The trailing ! forces that exact subkey. Without it, GPG may choose another key from the same certificate that it cannot use.
Step 4 — Check expiry Jump to heading
An expired signing subkey produces “unusable secret key” or simply fails. It happens exactly on the anniversary you set a year ago, which is why it feels like it broke for no reason.
gpg --list-keys --with-colons "$(git config user.signingKey | tr -d '!')" |
awk -F: '$1 ~ /pub|sub/ {print $1, $5, "expires:", ($7 ? strftime("%F", $7) : "never")}' If the subkey is expired, extend it — which needs the primary — or add a new subkey. Extending is quicker and keeps the same key ID:
# With the primary key available (offline machine or temporary GNUPGHOME)
gpg --quick-set-expire "$PRIMARY_FPR" 1y "$SUBKEY_FPR"
gpg --export --armor "$PRIMARY_FPR" > pub.asc # re-upload to the forge Step 5 — Restart a stuck agent Jump to heading
After sleep, a socket change, or an upgrade, the agent can hang or point at a stale socket. Restarting it is cheap and safe.
gpgconf --kill gpg-agent
gpg-connect-agent /bye # starts a fresh agent
gpgconf --list-dirs agent-socket # the socket every client should use If you use the agent for SSH authentication as well, set SSH_AUTH_SOCK from gpgconf --list-dirs agent-ssh-socket so the two do not disagree.
Step 6 — Check gpg.program and the environment Git runs in Jump to heading
If you set gpg.program to gpg2, a Homebrew path, or a Windows path, and that binary moved, Git fails with the same message. Hooks and GUI clients also run with a different PATH and HOME, so a bare gpg can resolve to a different binary with a different keyring.
git config --show-origin --get gpg.program
command -v "$(git config --get gpg.program || echo gpg)"
# Use an absolute path to remove ambiguity
git config --global gpg.program "$(command -v gpg)" For SSH signing, the equivalent setting is gpg.ssh.program, and the equivalent failure is an ssh-keygen that predates -Y sign support.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Why does signing work in my terminal but not in the editor? Jump to heading
The editor starts Git without your shell’s environment: no GPG_TTY, sometimes a different PATH. A graphical pinentry and an absolute gpg.program remove both dependencies. On Windows with WSL there may also be a different Git involved; see signing commits on Windows and WSL.
Can I just turn off signing to get the commit through? Jump to heading
git commit --no-gpg-sign creates an unsigned commit, which a signature gate will reject later. It is a reasonable way to save work in an emergency, but re-sign before pushing: git commit --amend --no-edit -S once signing works.
Does this error ever mean the commit content is the problem? Jump to heading
No. The commit object is just bytes to the signing program. The cause is always the program, the key, the agent or the environment.
Related Jump to heading
- GPG vs SSH Commit Signing — the parent topic.
- Setting Up GPG Commit Signing with Subkeys — a setup that avoids most of these causes.
- Setting Expiry and Renewal Reminders for Signing Keys — so step 4 never surprises you again.
- Setting Up SSH Commit Signing from Scratch — the simpler alternative if GPG keeps fighting you.