cli/cli · error
unable to delete GPG key %s: either the GPG key is not found
Error message
unable to delete GPG key %s: either the GPG key is not found or it is not owned by you
What it means
Thrown by gh gpg-key delete after it listed all GPG keys on the account and found none whose KeyID equals --key-id. The deletion endpoint needs the database ID, so a miss on the local lookup produces this combined not-found/not-yours message before any API mutation is attempted.
Source
Thrown at pkg/cmd/gpg-key/delete/delete.go:83
return err
}
host, _ := cfg.Authentication().DefaultHost()
gpgKeys, err := getGPGKeys(httpClient, host)
if err != nil {
return err
}
id := ""
for _, gpgKey := range gpgKeys {
if gpgKey.KeyID == opts.KeyID {
id = strconv.FormatInt(gpgKey.ID, 10)
break
}
}
if id == "" {
return fmt.Errorf("unable to delete GPG key %s: either the GPG key is not found or it is not owned by you", opts.KeyID)
}
if !opts.Confirmed {
if err := opts.Prompter.ConfirmDeletion(opts.KeyID); err != nil {
return err
}
}
err = deleteGPGKey(httpClient, host, id)
if err != nil {
return err
}
if opts.IO.IsStdoutTTY() {
cs := opts.IO.ColorScheme()
fmt.Fprintf(opts.IO.Out, "%s GPG key %s deleted from your account\n", cs.SuccessIcon(), opts.KeyID)
}
View on GitHub (pinned to 0eeec0b92e)
Solutions
- List your keys and copy the exact ID: `gh gpg-key list`.
- Confirm you are on the right host/account: `gh auth status`; switch with `gh auth switch`.
- If the key is already absent, no action is needed; the delete goal is already met.
Example fix
# before gh gpg-key delete "4CAE 5D6F ..." # fingerprint passed # gh: unable to delete GPG key ...: either the GPG key is not found or it is not owned by you # after gh gpg-key list # shows KeyID 3AA5C34371567BD2 gh gpg-key delete 3AA5C34371567BD2
Defensive patterns
Strategy: validation
Validate before calling
// Resolve the key against the account list before deleting:
keys, err := getGPGKeys(httpClient, host)
if err != nil { return err }
found := false
for _, k := range keys {
if k.KeyID == opts.KeyID { found = true; break }
}
if !found {
// print available KeyIDs so the user can correct the argument
return fmt.Errorf("key %s not in account; run `gh gpg-key list`", opts.KeyID)
} Type guard
func keyExists(keys []gpgKey, keyID string) bool {
for _, k := range keys {
if k.KeyID == keyID { return true }
}
return false
} Try / catch
if err := deleteRun(opts); err != nil {
if strings.Contains(err.Error(), "unable to delete GPG key") {
// run `gh gpg-key list`, compare KeyIDs exactly, retry or treat as already-deleted
}
} Prevention
- Always copy the KeyID from `gh gpg-key list`, not from gpg --list-keys fingerprints.
- Confirm host/account with `gh auth status` before deleting.
- Treat 'already removed' as success in idempotent cleanup scripts.
When it happens
Trigger: `gh gpg-key delete ABC1234D` with a mistyped or wrong-case key ID, a key uploaded to a different account/host, or a key already removed. The comparison is against the short/long key IDs returned by the list API.
Common situations: Using the fingerprint instead of the key ID, using the key ID from a work account against a personal GH_HOST, or repeating a delete that already succeeded.
Related errors
- gist not found: %s
- a value is required
- a task description is required
- no codespaces to delete
- could not find key "oauth_token"
AI-assisted analysis of cli/cli@0eeec0b92e (2026-08-15).
Data as JSON: /api/errors/6345c8b3b38ae108.
Report an issue: GitHub.