The 'gpg failed to sign the data' error with 'can't connect to the gpg-agent' occurs when the GPG agent daemon is not running or is inaccessible. This prevents Git from creating cryptographic signatures for commits and tags. The fix typically involves starting the agent or configuring the GPG_TTY environment variable.
The "gpg failed to sign the data: can't connect to the gpg-agent" error indicates that Git invoked GPG to sign a commit or tag, but GPG could not communicate with its agent daemon. The gpg-agent is a background process that manages private keys and caches passphrases, allowing GPG operations without repeatedly prompting for your passphrase. When this connection fails, GPG cannot access your signing key, causing the entire commit operation to fail. This commonly happens in new terminal sessions, after system reboots, in SSH sessions without proper TTY forwarding, or in environments like Docker containers or CI pipelines where the agent wasn't started. The gpg-agent communicates through a Unix socket file. If this socket doesn't exist, has wrong permissions, or the agent process isn't running, you'll see this error. Modern GPG versions (2.1+) start the agent automatically on first use, but various conditions can prevent this auto-start from working correctly.
First, try starting the gpg-agent daemon:
# Start gpg-agent in daemon mode
gpg-agent --daemon
# Or use gpgconf to launch it
gpgconf --launch gpg-agentIf the agent is already running but stuck, restart it:
# Kill any existing agent
gpgconf --kill gpg-agent
# Start fresh
gpg-agent --daemonVerify the agent is running:
# Check if agent process exists
pgrep -l gpg-agent
# Or check the socket
ls -la ~/.gnupg/S.gpg-agentGPG needs to know which terminal to use for passphrase prompts. Set GPG_TTY in your shell:
# Set for current session
export GPG_TTY=$(tty)
# Test signing now
echo "test" | gpg --clearsignAdd to your shell configuration for persistence:
# For bash (~/.bashrc or ~/.bash_profile)
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
source ~/.bashrc
# For zsh (~/.zshrc)
echo 'export GPG_TTY=$(tty)' >> ~/.zshrc
source ~/.zshrc
# For fish (~/.config/fish/config.fish)
echo 'set -x GPG_TTY (tty)' >> ~/.config/fish/config.fishThis is essential for GPG to prompt for passphrases in your terminal.
Ensure gpg-agent starts automatically when needed. Add these lines to ~/.gnupg/gpg.conf:
# Create or edit gpg.conf
mkdir -p ~/.gnupg
cat >> ~/.gnupg/gpg.conf << 'EOF'
use-agent
EOFAnd configure the agent in ~/.gnupg/gpg-agent.conf:
cat >> ~/.gnupg/gpg-agent.conf << 'EOF'
# Cache passphrase for 1 hour
default-cache-ttl 3600
max-cache-ttl 7200
# Allow loopback pinentry for non-TTY environments
allow-loopback-pinentry
EOFReload the agent configuration:
gpg-connect-agent reloadagent /byeIncorrect permissions on the GPG directory can prevent agent communication:
# Set correct permissions
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*
# Fix socket permissions if they exist
chmod 600 ~/.gnupg/S.gpg-agent* 2>/dev/null || trueIf the socket directory is wrong, you may need to recreate it:
# Remove stale sockets
rm -f ~/.gnupg/S.gpg-agent*
# Restart agent to recreate sockets
gpgconf --kill gpg-agent
gpgconf --launch gpg-agentIn non-interactive environments (CI/CD, cron, scripts), configure GPG to use loopback pinentry:
# Add to gpg-agent.conf
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
# Reload agent
gpg-connect-agent reloadagent /byeFor Git specifically, you can set this in your Git config:
git config --global gpg.program gpgAnd when signing, use the loopback mode:
# In scripts, use:
echo "passphrase" | gpg --batch --yes --pinentry-mode loopback \
--passphrase-fd 0 --sign file.txt
# For Git commits in CI, consider using:
git -c gpg.program="gpg --batch --pinentry-mode loopback" commit -S -m "message"Security note: Avoid hardcoding passphrases. Use CI secrets or pre-import keys without passphrases for automation.
On macOS, Homebrew's GPG may conflict with system tools. Configure pinentry properly:
# Install pinentry-mac if not present
brew install pinentry-mac
# Configure gpg-agent to use pinentry-mac
echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.conf
# Restart the agent
gpgconf --kill gpg-agentAlso ensure GPG_TTY is set in your shell profile:
# Add to ~/.zshrc (default macOS shell)
export GPG_TTY=$(tty)If you're using the GPG Suite app, it includes its own agent. Check for conflicts:
# See which gpg is being used
which gpg
gpg --version
# Should be Homebrew's: /opt/homebrew/bin/gpg or /usr/local/bin/gpgWSL2 has specific issues with GPG agent. The agent runs inside WSL, not Windows:
# Ensure GPG_TTY is set
export GPG_TTY=$(tty)
# Start agent if not running
gpgconf --launch gpg-agent
# Add to ~/.bashrc
cat >> ~/.bashrc << 'EOF'
export GPG_TTY=$(tty)
gpgconf --launch gpg-agent >/dev/null 2>&1
EOFIf you want to share Windows GPG keys with WSL:
# Option 1: Copy keys from Windows
# In WSL:
cp -r /mnt/c/Users/YOUR_USERNAME/AppData/Roaming/gnupg/* ~/.gnupg/
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*
# Option 2: Use npiperelay to forward Windows gpg-agent (advanced)
# See: https://github.com/NZSmartie/npiperelayAlternatively, generate separate keys for WSL and add both to GitHub/GitLab.
In Docker, the gpg-agent needs to be available within the container:
# In your Dockerfile
RUN apt-get update && apt-get install -y gnupg2
# Copy GPG keys (not recommended for production - use secrets)
COPY --chown=user:user .gnupg /home/user/.gnupgFor CI/CD, import keys at runtime:
# Import private key from environment variable
echo "$GPG_PRIVATE_KEY" | base64 -d | gpg --batch --import
# Trust the key
echo "$GPG_KEY_ID:6:" | gpg --import-ownertrust
# Configure for non-interactive use
mkdir -p ~/.gnupg
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
# Start agent
gpgconf --launch gpg-agent
export GPG_TTY=$(tty)Use the key ID to configure Git:
git config --global user.signingkey $GPG_KEY_ID
git config --global commit.gpgsign trueAfter applying fixes, test GPG signing:
# Test GPG directly
echo "test" | gpg --clearsign
# Should prompt for passphrase and output signed message
# Test with Git
git commit --allow-empty -S -m "Test signed commit"
# Verify the signature
git log --show-signature -1If successful, you should see no agent connection errors and the commit should be signed.
If you need to commit urgently while debugging:
# Single commit without signing
git commit --no-gpg-sign -m "Your commit message"
# Or disable signing temporarily
git config --global commit.gpgsign false
# Remember to re-enable later!
git config --global commit.gpgsign trueFor a specific repository only:
git config --local commit.gpgsign false### How GPG Agent Works
The gpg-agent is a daemon that:
- Holds private keys in memory after you unlock them
- Caches passphrases so you don't re-enter them constantly
- Manages access to keys for multiple GPG operations
- Communicates via Unix sockets (files like ~/.gnupg/S.gpg-agent)
When Git calls gpg --sign, GPG connects to this agent to request the private key operation.
### Understanding Pinentry
Pinentry is a separate program that GPG uses to ask for your passphrase:
- pinentry-curses: Text-based, works in terminals
- pinentry-gtk/qt: Graphical popup dialogs
- pinentry-mac: macOS native dialog
- pinentry-tty: Simple TTY-based entry
If the wrong pinentry is configured, or none can run (no display, no TTY), the agent connection appears to fail.
### Systemd User Services
On modern Linux with systemd, gpg-agent can run as a user service:
# Enable gpg-agent socket activation
systemctl --user enable gpg-agent.socket
systemctl --user start gpg-agent.socket
# Check status
systemctl --user status gpg-agentThis provides automatic agent startup when needed.
### SSH Agent Integration
GPG agent can also serve as an SSH agent:
# Add to gpg-agent.conf
enable-ssh-support
# Add to shell profile
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)This allows using GPG keys for SSH authentication.
### Debugging Agent Issues
For detailed debugging:
# Check agent socket location
gpgconf --list-dirs agent-socket
# Test agent connection
gpg-connect-agent /bye
# Verbose GPG output
gpg -v --sign test.txt
# Check environment
env | grep -E '(GPG|SSH)'### Multiple Home Directories
If you use multiple GNUPGHOME directories:
# Set custom GPG home
export GNUPGHOME=~/.gnupg-work
# Agent socket will be in that directory
gpgconf --list-dirs agent-socketEach GNUPGHOME has its own agent instance.
### Remote GPG Agent (SSH)
When SSH-ing to remote machines, the agent doesn't follow by default. Options:
1. Run agent on remote: Start gpg-agent on the remote server
2. Forward agent socket: Use SSH socket forwarding (complex setup)
3. Use SSH agent instead: For signing, consider SSH signatures (Git 2.34+)
# Git 2.34+ supports SSH signing as alternative to GPG
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pubkex_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