The 'gpg failed to sign the data' error with 'No pinentry' occurs when GPG cannot find or access the pinentry program needed to prompt for your passphrase. This typically happens after system updates, in SSH sessions, or when the GPG agent configuration is missing or incorrect.
The "gpg failed to sign the data" error with "problem with the agent: No pinentry" indicates that GPG's agent cannot locate or launch the pinentry program. Pinentry is a helper application that securely prompts you for your GPG key passphraseβwithout it, GPG cannot unlock your private key to create signatures. When you run a Git command that requires signing (like `git commit -S` or when `commit.gpgsign` is enabled), Git invokes GPG to sign the data. GPG then contacts the gpg-agent, which needs to ask for your passphrase. The agent delegates this to a pinentry program, but if pinentry is missing, misconfigured, or incompatible with your current environment (such as a headless SSH session), the signing process fails. This error is common after OS upgrades, when switching between GUI and terminal sessions, in CI/CD pipelines, or when using remote connections where no display is available for graphical passphrase prompts.
First, check if a pinentry program exists on your system:
# Find pinentry binaries
which pinentry pinentry-tty pinentry-curses pinentry-mac pinentry-gnome3 2>/dev/null
# On Linux, check common locations
ls -la /usr/bin/pinentry* 2>/dev/null
# On macOS with Homebrew
ls -la $(brew --prefix)/bin/pinentry* 2>/dev/nullIf no pinentry is found, you need to install one:
On Ubuntu/Debian:
sudo apt update
sudo apt install pinentry-tty
# Or for GUI: sudo apt install pinentry-gnome3On Fedora/RHEL/CentOS:
sudo dnf install pinentry
# Or: sudo yum install pinentryOn macOS:
brew install pinentry-mac
# Or for CLI: brew install pinentryOn Arch Linux:
sudo pacman -S pinentryCreate or update the GPG agent configuration file:
# Create the .gnupg directory if it doesn't exist
mkdir -p ~/.gnupg
chmod 700 ~/.gnupg
# Find your pinentry path
PINENTRY_PATH=$(which pinentry-tty || which pinentry || which pinentry-curses)
echo "Pinentry found at: $PINENTRY_PATH"
# Add to gpg-agent.conf
echo "pinentry-program $PINENTRY_PATH" >> ~/.gnupg/gpg-agent.confFor macOS with pinentry-mac:
echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" >> ~/.gnupg/gpg-agent.confFor Linux GUI environments:
# GNOME
echo "pinentry-program /usr/bin/pinentry-gnome3" >> ~/.gnupg/gpg-agent.conf
# KDE
echo "pinentry-program /usr/bin/pinentry-qt" >> ~/.gnupg/gpg-agent.confView your configuration:
cat ~/.gnupg/gpg-agent.confAfter configuration changes, restart the GPG agent:
# Kill the existing agent
gpgconf --kill gpg-agent
# Or use pkill
pkill gpg-agent
# The agent will restart automatically on next GPG use
# Or start it manually:
gpg-agent --daemonVerify the agent is running with the new configuration:
gpgconf --list-components
gpg-agent --versionFor terminal-based pinentry to work, GPG needs to know which terminal to use:
# Set GPG_TTY for current session
export GPG_TTY=$(tty)
# Add to your shell profile for persistence
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
# Or for zsh:
echo 'export GPG_TTY=$(tty)' >> ~/.zshrc
# Reload your profile
source ~/.bashrc # or source ~/.zshrcThis is especially important for:
- SSH sessions
- Terminal multiplexers (tmux, screen)
- WSL environments
- Headless servers
Verify that signing now works:
# Test GPG signing directly
echo "test" | gpg --clearsign
# You should see output like:
# -----BEGIN PGP SIGNED MESSAGE-----
# Hash: SHA256
#
# test
# -----BEGIN PGP SIGNATURE-----
# ...
# -----END PGP SIGNATURE-----If this works, test Git signing:
# Create a test signed commit
git commit --allow-empty -S -m "Test signed commit"
# Verify the signature
git log --show-signature -1If standard pinentry doesn't work (common in CI/CD or Docker), use loopback mode:
# Add to ~/.gnupg/gpg.conf
echo "use-agent" >> ~/.gnupg/gpg.conf
echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
# Add to ~/.gnupg/gpg-agent.conf
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
# Restart agent
gpgconf --kill gpg-agentWith loopback mode, GPG will prompt for the passphrase directly in the terminal instead of using a separate pinentry program.
Note: This is less secure than using a proper pinentry program, but useful for automated environments.
When connecting via SSH, GUI pinentry programs fail because there's no display:
# Use TTY-based pinentry for SSH sessions
# In ~/.gnupg/gpg-agent.conf:
pinentry-program /usr/bin/pinentry-tty
# Or use curses-based for better interface:
pinentry-program /usr/bin/pinentry-cursesYou can also configure conditional pinentry selection in your shell profile:
# Add to ~/.bashrc or ~/.zshrc
if [[ -n "$SSH_CONNECTION" ]]; then
export GPG_TTY=$(tty)
# Optionally update agent config for TTY pinentry
fiAfter making changes:
gpgconf --kill gpg-agentOn macOS, the recommended solution is using pinentry-mac which integrates with Keychain:
# Install pinentry-mac
brew install pinentry-mac
# Configure GPG to use it
echo "pinentry-program $(brew --prefix)/bin/pinentry-mac" > ~/.gnupg/gpg-agent.conf
# Restart the agent
gpgconf --kill gpg-agent
# Test
echo "test" | gpg --clearsignIf you previously had GPG Suite installed and it was updated or removed:
# Reinstall GPG Suite
brew reinstall --cask gpg-suite
# Or use standalone GPG
brew reinstall gnupg pinentry-macNote: pinentry-mac allows saving your passphrase in macOS Keychain, reducing passphrase prompts.
Windows Subsystem for Linux requires additional configuration:
# Install pinentry
sudo apt install pinentry-tty
# Configure GPG agent
mkdir -p ~/.gnupg
chmod 700 ~/.gnupg
cat > ~/.gnupg/gpg-agent.conf << 'EOF'
pinentry-program /usr/bin/pinentry-tty
allow-loopback-pinentry
EOF
cat > ~/.gnupg/gpg.conf << 'EOF'
use-agent
pinentry-mode loopback
EOF
# Set permissions
chmod 600 ~/.gnupg/*
# Add to ~/.bashrc
echo 'export GPG_TTY=$(tty)' >> ~/.bashrc
source ~/.bashrc
# Restart agent
gpgconf --kill gpg-agentFor WSL2, the loopback pinentry mode often works best since there's no native display forwarding.
If issues persist, debug the GPG configuration:
# Check GPG configuration
gpgconf --list-dirs
gpgconf --list-options gpg-agent
# Verify agent socket exists
ls -la $(gpgconf --list-dirs agent-socket)
# Test agent connection
gpg-connect-agent /bye
# Enable verbose output for Git
GIT_TRACE=1 git commit --allow-empty -S -m "Debug test"
# Check GPG directly with verbose output
echo "test" | gpg --verbose --clearsignCommon issues to look for:
- Socket permission problems
- Multiple GPG installations conflicting
- Incorrect home directory permissions
### Understanding Pinentry
Pinentry is a collection of passphrase dialog programs. Different variants exist for different environments:
| Program | Environment | Notes |
|---------|-------------|-------|
| pinentry-tty | Basic terminal | Works everywhere, minimal interface |
| pinentry-curses | Terminal | Better UI with ncurses |
| pinentry-gnome3 | GNOME | Native GTK3 dialogs |
| pinentry-qt | KDE | Native Qt dialogs |
| pinentry-mac | macOS | Keychain integration |
### Cache Passphrase to Reduce Prompts
Configure the agent to cache your passphrase:
# In ~/.gnupg/gpg-agent.conf
default-cache-ttl 3600 # Cache for 1 hour
max-cache-ttl 86400 # Maximum cache of 24 hoursRestart agent after changes: gpgconf --kill gpg-agent
### Multiple Pinentry Programs
You can use update-alternatives on Linux to switch between pinentry programs:
# View available pinentry options
sudo update-alternatives --config pinentry
# Set pinentry-tty as default
sudo update-alternatives --set pinentry /usr/bin/pinentry-tty### CI/CD Pipeline Configuration
For automated environments without interactive prompts:
# Import key non-interactively
echo "$GPG_PRIVATE_KEY" | gpg --batch --import
# Sign commits using cached passphrase or preset passphrase
gpg --batch --pinentry-mode loopback --passphrase "$GPG_PASSPHRASE" ...Or configure Git to use a specific GPG with preset passphrase handling.
### Docker Container Setup
For signing commits in Docker:
RUN apt-get update && apt-get install -y gnupg pinentry-tty
# Copy GPG configuration
COPY .gnupg/gpg.conf /root/.gnupg/
COPY .gnupg/gpg-agent.conf /root/.gnupg/
# Set permissions
RUN chmod 700 /root/.gnupg && chmod 600 /root/.gnupg/*### Temporarily Disable Signing
If you need to commit urgently while troubleshooting:
# Single commit without signing
git commit --no-gpg-sign -m "message"
# Disable signing temporarily
git config --global commit.gpgsign false
# Re-enable when fixed
git config --global commit.gpgsign true### Socket Issues
If the agent socket has permission issues:
# Remove stale socket
rm -f $(gpgconf --list-dirs agent-socket)
# Restart agent
gpgconf --kill gpg-agent
gpg-agent --daemon### Debugging Agent Communication
# Check agent status
gpg-connect-agent 'getinfo version' /bye
# List cached keys
gpg-connect-agent 'keyinfo --list' /bye
# Reload agent configuration
gpg-connect-agent reloadagent /byekex_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