This GPG error occurs when Git cannot use your GPG key for signing commits or tags. The key may be expired, lack signing capability, or have trust issues. Fixing it involves checking key status and renewing or reconfiguring the key.
When you sign Git commits or tags with GPG, Git uses the `gpg` command to create cryptographic signatures. The "unusable public key" error means GPG found your key but cannot use it for the requested operation. GPG keys have capabilities and expiration dates. A key might be flagged for encryption only (E) but not signing (S), or the key/subkey may have expired. GPG also requires keys to have a minimum trust level before using them for certain operations. This error commonly occurs when: - Your GPG key or its signing subkey has expired - The key lacks the signing capability flag [S] - You migrated keys between machines without proper trust settings - The public key is missing required subkeys (common after partial key exports) - GPG version mismatch between when the key was created and current usage
First, list your GPG keys to identify the problem:
gpg --list-keys --keyid-format LONGLook for your key and check for:
- Expiration: Does it show expired next to the key?
- Capabilities: Look for [SC] (Sign, Certify) or [S] (Sign only)
Example output:
pub rsa4096/30F2B65B9246B6CA 2022-01-15 [SC] [expired: 2024-01-15]
Key fingerprint = ABCD 1234 5678 EFGH...
uid [expired] Your Name <[email protected]>
sub rsa4096/B7ABC0813E4028C0 2022-01-15 [E] [expired: 2024-01-15]If you see [expired], proceed to renew the key. If you only see [E] without [S], the key cannot sign.
Verify you have the secret (private) key, not just the public key:
gpg --list-secret-keys --keyid-format LONGIf this returns empty but --list-keys shows your key, you only have the public key. You need to import your private key:
gpg --import your-private-key.ascAfter importing, verify it appears in the secret keys list.
If your key expired, you can extend its validity:
gpg --edit-key YOUR_KEY_IDAt the gpg> prompt:
gpg> expireEnter a new expiration period (e.g., 1y for one year, 0 for never expires).
If you have subkeys, select and renew each one:
gpg> key 1
gpg> expire
gpg> key 2
gpg> expireSave changes:
gpg> saveAfter renewing, export and update your public key on GitHub/GitLab:
gpg --armor --export YOUR_KEY_IDIf the key is valid but untrusted, set its trust level:
gpg --edit-key YOUR_KEY_IDAt the gpg> prompt:
gpg> trustSelect option 5 (ultimate trust) for your own key:
Please decide how far you trust this user to correctly verify other users' keys
1 = I don't know or won't say
2 = I do NOT trust
3 = I trust marginally
4 = I trust fully
5 = I trust ultimately
m = back to the main menu
Your decision? 5Confirm and save:
gpg> quitCheck which key Git is configured to use:
git config --global user.signingkeyThis should match a key ID from gpg --list-secret-keys. If empty or wrong, set it:
git config --global user.signingkey YOUR_KEY_IDAlso verify Git is using the correct GPG binary:
git config --global gpg.programIf you have gpg2, you may need:
git config --global gpg.program gpg2Or on macOS with Homebrew:
git config --global gpg.program /opt/homebrew/bin/gpgAfter fixing the key, test that signing works:
echo "test" | gpg --clearsignThis should prompt for your passphrase and output signed text. If this works, test Git:
git commit --allow-empty -S -m "Test signed commit"Verify the signature:
git log --show-signature -1You should see "Good signature from..." in the output.
### GPG Key Capability Flags
GPG keys have capability flags that determine what operations they can perform:
- [C] - Certify: Can sign other keys (master key only)
- [S] - Sign: Can create signatures (needed for Git commits)
- [E] - Encrypt: Can encrypt data
- [A] - Authenticate: Can authenticate (SSH, etc.)
If your key only shows [E], it's an encryption-only key and cannot sign. You'll need to either:
1. Create a new key with signing capability: gpg --full-generate-key
2. Add a signing subkey to your existing key: gpg --edit-key KEY_ID then addkey
### Migrating Keys Between Machines
When copying GPG keys to a new machine, export BOTH the public and secret keys:
# On source machine
gpg --export-secret-keys --armor YOUR_KEY_ID > private.asc
gpg --export --armor YOUR_KEY_ID > public.asc
gpg --export-ownertrust > trust.txt
# On target machine
gpg --import private.asc
gpg --import public.asc
gpg --import-ownertrust trust.txtWithout the trust database, your key may show as untrusted even with all key material present.
### GPG Agent Issues
Sometimes the GPG agent caches incorrect state. Restart it:
gpgconf --kill gpg-agent
gpg-agent --daemonOr reload:
gpg-connect-agent reloadagent /bye### Using Different GPG Versions
If you created keys with GPG 2.x but Git is using GPG 1.x (or vice versa), they may use different keyrings. Check versions:
gpg --version
gpg2 --versionList keys with both to see if they differ:
gpg --list-secret-keys --keyid-format LONG
gpg2 --list-secret-keys --keyid-format LONGConfigure Git to use the correct one:
git config --global gpg.program gpg2### Debugging with Verbose Output
For detailed troubleshooting, run GPG with debug flags:
gpg -v --debug-level guru --sign test.txtOr check Git's GPG interaction:
GIT_TRACE=1 git commit -S -m "test"### Creating a New Signing Subkey
If your key lacks signing capability, add a subkey:
gpg --edit-key YOUR_KEY_ID
gpg> addkeySelect RSA (sign only) and set desired key size and expiration. Then:
gpg> saveUpdate your public key on GitHub/GitLab after adding the subkey.
kex_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