The Error
You stage your changes in VS Code, hit commit โ and instead of a clean commit, you get:
error: gpg failed to sign the data
fatal: failed to write commit object
The Source Control panel shows a generic failure. No passphrase prompt, no hint about what went wrong. What makes it maddening: the same commit might work fine from a regular terminal. VS Code's integrated terminal and GUI commit flow are often the culprit โ they don't always inherit the full shell environment.
Why This Happens
With commit.gpgsign = true in your Git config, every commit must be signed. There are a handful of ways this can break:
- The GPG agent is not running or has crashed
GPG_TTYis not set, so GPG can't prompt for a passphrase- The pinentry program can't display a dialog (common in VS Code's terminal context)
- The configured signing key doesn't exist or has expired
- On macOS: GPG Suite's pinentry-mac isn't wired up correctly
VS Code makes this harder to debug. Its integrated terminal and GUI commit flow don't always inherit your full shell environment โ which means GPG_TTY goes unset and the agent socket may be missing, silently.
Fix 1: Restart the GPG Agent
Start here. Kill the agent and let it respawn on the next GPG call:
gpgconf --kill gpg-agent
gpg-agent --daemon
Try your commit again. If the agent had crashed or gotten into a bad state, this one step is often all it takes.
Fix 2: Set GPG_TTY in Your Shell Profile
GPG needs a TTY to show the passphrase prompt. In VS Code's integrated terminal, GPG_TTY is often not set โ which means the signing attempt fails silently.
Add this line to your ~/.bashrc, ~/.zshrc, or ~/.bash_profile:
export GPG_TTY=$(tty)
Reload your shell:
source ~/.zshrc # or ~/.bashrc
Open a fresh VS Code terminal and try committing again. On Linux, this is the most common fix.
Fix 3: Switch to pinentry-tty (Linux)
Still no passphrase dialog? Switch to the terminal-based pinentry. First, find where it lives on your system:
which pinentry-tty
# common paths: /usr/bin/pinentry-tty or /usr/local/bin/pinentry-tty
Then configure it and restart the agent:
echo "pinentry-program /usr/bin/pinentry-tty" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Test GPG directly before touching Git:
echo "test" | gpg --clearsign
If that prompts for your passphrase and signs cleanly, VS Code commits will work too.
Fix 4: macOS โ Use pinentry-mac
macOS is particular here. Without pinentry-mac, GPG has no way to show a dialog when called from VS Code's Source Control panel โ there's simply no terminal to prompt you in. Install it first:
brew install pinentry-mac
Then wire it up:
echo "pinentry-program $(which pinentry-mac)" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
After this, you'll get a native macOS passphrase dialog even when committing through the GUI โ no terminal required.
Fix 5: Check Your Signing Key
Worth ruling out: maybe Git is configured with a key that doesn't exist or has expired. Start by checking what Git thinks it should use:
git config --global user.signingkey
Then list what GPG actually has:
gpg --list-secret-keys --keyid-format LONG
You'll see output like:
sec rsa4096/3AA5C34371567BD2 2021-03-01 [SC]
...
uid Your Name <you@example.com>
The value after the / on the sec line is your key ID. If it doesn't match your Git config, update it:
git config --global user.signingkey 3AA5C34371567BD2
Also check the expiry dates in the output. An expired key needs to be renewed or replaced before signing will work again.
Fix 6: Commit from the Terminal (Workaround)
When the GUI commit flow keeps failing, bypass it. Open the integrated terminal and commit directly:
git commit -m "your message"
With GPG_TTY set in your shell profile and the agent running, this usually works. It sidesteps whatever environment problem VS Code's Source Control panel has.
Fix 7: Temporarily Disable GPG Signing
Need to ship something right now? Skip signing for this one commit:
git commit --no-gpg-sign -m "your message"
Or turn it off globally while you debug the root cause:
git config --global commit.gpgsign false
Re-enable it once the GPG setup is sorted:
git config --global commit.gpgsign true
Verifying the Fix
Before calling it done, run a quick end-to-end check:
# Confirm GPG can sign and the passphrase prompt works
echo "test" | gpg --clearsign
# Make an empty commit and inspect the signature
git commit --allow-empty -m "test gpg signing"
git log --show-signature -1
In the git log output, look for:
gpg: Signature made Wed Jul 16 10:00:00 2026 JST
gpg: using RSA key 3AA5C34371567BD2
gpg: Good signature from "Your Name <you@example.com>"
That "Good signature" line is what you're after. Everything is wired up correctly.
Prevention
A few habits that stop this from coming back:
- Add
export GPG_TTY=$(tty)to your shell profile permanently โ not just the current session - On macOS, use pinentry-mac so passphrase dialogs work everywhere, including GUI tools
- Keep an eye on key expiry:
gpg --list-keysshows the dates; set a calendar reminder when you renew - On multiple machines, import the GPG key on each one โ copying just the Git config isn't enough
- Consider SSH signing if you want less friction:
git config --global gpg.format ssh

