The 'gpg failed to sign the data' error with 'Unusable secret key (key expired)' occurs when your GPG signing key has passed its expiration date. Git cannot use an expired key to sign commits or tags, but you can renew the key's expiration without creating a new one.
The "gpg failed to sign the data" error with "Unusable secret key (key expired)" indicates that your GPG key's expiration date has passed. GPG keys can be configured with an expiration date as a security measure—a "dead-man switch" that prevents indefinite use of a key if it's compromised or abandoned. When you attempt to sign a Git commit or tag, Git invokes GPG to create a cryptographic signature. If the key specified in your `user.signingkey` configuration has expired, GPG refuses to use it, causing the commit to fail. This is a protective measure: expired keys shouldn't be trusted for new signatures. The good news is that GPG key expiration dates can be extended even after expiration. The private key itself never expires—only the public key's metadata contains the expiration date. You can renew your key, update the expiration date, and continue using the same key identity without losing your commit verification history.
First, confirm that key expiration is the actual issue:
# List your secret keys with expiration dates
gpg --list-secret-keys --keyid-format=long
# Look for output like:
# sec rsa4096/ABC123DEF456 2020-01-15 [SC] [expired: 2024-01-15]
# Fingerprint: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
# uid [ expired] Your Name <[email protected]>If you see [expired: DATE] next to your key, the expiration date has passed.
You can also test signing directly:
# Replace ABC123DEF456 with your key ID
echo "test" | gpg --clearsign -u ABC123DEF456
# If expired, you'll see:
# gpg: signing failed: Unusable secret keyIdentify the key ID you need to renew:
# List keys with long format IDs
gpg --list-secret-keys --keyid-format=long
# Output example:
# sec rsa4096/ABC123DEF456789AB 2020-01-15 [SC] [expired: 2024-01-15]
# XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
# uid [ expired] John Doe <[email protected]>
# ssb rsa4096/DEF789GHI123456CD 2020-01-15 [E] [expired: 2024-01-15]The key ID is the part after the slash on the sec line (e.g., ABC123DEF456789AB).
You can also check which key Git is configured to use:
# Check global config
git config --global user.signingkey
# Check local repo config (may override global)
git config --local user.signingkeyRenew your key by editing it in GPG's interactive mode:
# Start editing the key (use your key ID)
gpg --edit-key ABC123DEF456789ABIn the GPG interactive prompt:
gpg> expire
Changing expiration time for the primary key.
Please specify how long the key should be valid.
0 = key does not expire
<n> = key expires in n days
<n>w = key expires in n weeks
<n>m = key expires in n months
<n>y = key expires in n years
Key is valid for? (0) 1yEnter your desired validity period (e.g., 1y for one year, 2y for two years, or 0 for no expiration).
You'll be prompted to confirm and enter your passphrase:
Is this correct? (y/N) y
You need a passphrase to unlock the secret key for
user: "John Doe <[email protected]>"If you have signing or encryption subkeys, update them too:
gpg> list
# Shows all keys and subkeys with numbers
gpg> key 1
# Selects the first subkey (an asterisk appears next to it)
gpg> expire
Key is valid for? (0) 1y
Is this correct? (y/N) y
# If you have more subkeys, repeat:
gpg> key 1
# Deselects key 1
gpg> key 2
# Selects key 2
gpg> expire
...After updating all keys:
gpg> saveThis saves the changes and exits the GPG prompt.
Confirm the key now has a valid expiration date:
# List keys again
gpg --list-secret-keys --keyid-format=long
# Should now show future date:
# sec rsa4096/ABC123DEF456789AB 2020-01-15 [SC] [expires: 2025-12-01]Test signing:
echo "test" | gpg --clearsign -u ABC123DEF456789AB
# Should produce a signed message without errorsTest a Git commit:
git commit --allow-empty -S -m "Test signed commit"
# Should succeed without GPG errorsAfter renewing, you must update your public key on hosting platforms:
# Export your renewed public key
gpg --armor --export ABC123DEF456789ABFor GitHub:
1. Go to Settings → SSH and GPG keys
2. Delete the old GPG key entry
3. Click "New GPG key"
4. Paste the exported public key
5. Save
For GitLab:
1. Go to User Settings → GPG Keys
2. Remove the old key
3. Add the new public key
Note: Previously signed commits will remain verified because the signature was valid at the time of signing. The renewed key maintains the same identity.
If you use public keyservers, update them with your renewed key:
# Send to Ubuntu keyserver
gpg --keyserver keyserver.ubuntu.com --send-keys ABC123DEF456789AB
# Send to MIT keyserver
gpg --keyserver pgp.mit.edu --send-keys ABC123DEF456789AB
# Send to keys.openpgp.org (requires email verification)
gpg --keyserver keys.openpgp.org --send-keys ABC123DEF456789ABThis allows others who verify your signatures to get the updated expiration date.
For GPG version 2.1.22 or later, you can use a non-interactive command:
# Get your key fingerprint
gpg --list-secret-keys --keyid-format=long
# Extend primary key expiration by 1 year
gpg --quick-set-expire FINGERPRINT 1y
# Example with full fingerprint:
gpg --quick-set-expire XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 1yTo also update subkeys:
# List subkey fingerprints
gpg --list-keys --with-subkey-fingerprint ABC123DEF456789AB
# Update each subkey
gpg --quick-set-expire SUBKEY_FINGERPRINT 1yYou can specify exact dates using ISO format (2025-12-31) or relative periods (6m, 2y).
If your repository has a local key configuration pointing to an expired key:
# Check if local config overrides global
git config --local user.signingkey
# If it shows an old/expired key, remove it
git config --local --unset user.signingkey
# Or update it to your current key
git config --local user.signingkey ABC123DEF456789ABVerify Git is now using the correct key:
git config user.signingkey### Understanding GPG Key Expiration
GPG key expiration is a security feature, not a limitation:
- Private keys never expire — only the public key metadata contains the expiration date
- Expired keys can still be renewed — you always have full control over keys you own
- Signatures made before expiration remain valid — the expiration affects future use only
- Expiration acts as a dead-man switch — if you lose access, the key automatically becomes untrusted
### Setting Appropriate Expiration Periods
Best practices for expiration dates:
- 1-2 years is a good balance between security and convenience
- Never set no expiration for keys used in production environments
- Shorter periods (3-6 months) for high-security environments
- Set calendar reminders to renew before expiration
### Backing Up Your Key
After renewal, back up your key:
# Export secret key (keep this secure!)
gpg --export-secret-keys --armor ABC123DEF456789AB > private-key-backup.asc
# Export public key
gpg --export --armor ABC123DEF456789AB > public-key-backup.asc
# Export trust database
gpg --export-ownertrust > trustdb-backup.txtStore backups in a secure location (encrypted drive, password manager, etc.).
### Multiple Keys Scenario
If you have multiple GPG keys:
# List all secret keys
gpg --list-secret-keys
# Set the correct one as default for Git
git config --global user.signingkey CORRECT_KEY_ID
# Optionally, delete old/unused keys
gpg --delete-secret-keys OLD_KEY_ID
gpg --delete-keys OLD_KEY_ID### Disabling Commit Signing Temporarily
If you need to commit urgently while fixing the key:
# Single commit without signing
git commit --no-gpg-sign -m "Your message"
# Or disable globally temporarily
git config --global commit.gpgsign false
# Don't forget to re-enable later
git config --global commit.gpgsign true### Signing With a Specific Key
If you have multiple keys, specify which to use:
# Per-repository
git config user.signingkey SPECIFIC_KEY_ID
# Or per-commit
git commit -S<keyid> -m "Message"### WSL and Windows Considerations
On Windows Subsystem for Linux (WSL):
- Ensure GPG agent is running: gpg-agent --daemon
- You may need to set GPG_TTY: export GPG_TTY=$(tty)
- Consider using Windows GPG with Git for Windows instead
### Troubleshooting GPG Agent
If issues persist after renewal:
# Restart GPG agent
gpgconf --kill gpg-agent
gpg-agent --daemon
# Clear cached passphrases
echo RELOADAGENT | gpg-connect-agentkex_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