AlistGo/alist · error
signing failed: %v
Error message
signing failed: %v
What it means
Thrown by the GitHub driver when creating a release commit signature: openpgp.DetachSign fails to produce a detached PGP signature over the commit payload. The signing entity is derived from the driver's configured GPG private key, so failure almost always means the key could not be parsed, is encrypted with a passphrase (which x/crypto/openpgp cannot unlock here since nil config is passed), or has no private-key material. It surfaces as 'signing failed: <openpgp error>'.
Source
Thrown at drivers/github/util.go:154
for _, p := range parents {
commit.WriteString(fmt.Sprintf("parent %s\n", p))
}
now := time.Now()
_, offset := now.Zone()
hour := offset / 3600
author := (*m)["author"].(map[string]string)
commit.WriteString(fmt.Sprintf("author %s <%s> %d %+03d00\n", author["name"], author["email"], now.Unix(), hour))
author["date"] = now.Format(time.RFC3339)
committer := (*m)["committer"].(map[string]string)
commit.WriteString(fmt.Sprintf("committer %s <%s> %d %+03d00\n", committer["name"], committer["email"], now.Unix(), hour))
committer["date"] = now.Format(time.RFC3339)
commit.WriteString(fmt.Sprintf("\n%s", (*m)["message"].(string)))
data := commit.String()
var sigBuffer bytes.Buffer
err := openpgp.DetachSign(&sigBuffer, entity, strings.NewReader(data), nil)
if err != nil {
return "", fmt.Errorf("signing failed: %v", err)
}
var armoredSig bytes.Buffer
armorWriter, err := armor.Encode(&armoredSig, "PGP SIGNATURE", nil)
if err != nil {
return "", err
}
if _, err = utils.CopyWithBuffer(armorWriter, &sigBuffer); err != nil {
return "", err
}
_ = armorWriter.Close()
return armoredSig.String(), nil
}
View on GitHub (pinned to 843d9dc814)
Solutions
- Re-export the private key without a passphrase: gpg --export-secret-keys --armor KEYID and paste the full ARMORED block including headers
- Verify the key parses standalone: gpg --list-packets key.asc or try signing with gpg --detach-sign locally
- Check the driver's key parsing code path (entity creation from config) and its error, since the %v in 'signing failed' carries the exact openpgp reason
- If a passphrase is mandatory, decrypt first: gpg --export-options export-reset-subkey-passwd --export-secret-keys, or use a key without passphrase
Example fix
// before: passphrase-protected or public key in config d.Addition.PrivateKey = publicKeyArmored // DetachSign fails: signing failed: openpgp: ... // after: export unencrypted private key d.Addition.PrivateKey = privateKeyArmored // gpg --export-secret-keys --armor KEYID
Defensive patterns
Strategy: validation
Validate before calling
// Validate the armored private key parses and holds a private entity before Init
import (
"crypto/openpgp"
"strings"
)
func validSigningKey(armored string) bool {
if armored == "" { return false }
entityList, err := openpgp.ReadArmoredKeyRing(strings.NewReader(armored))
return err == nil && len(entityList) == 1 && entityList[0].PrivateKey != nil && !entityList[0].PrivateKey.Encrypted
} Try / catch
err := driver.Init(ctx)
if err != nil {
if strings.Contains(err.Error(), "signing failed") {
// key material problem: fix config, do not retry
}
} Prevention
- Store the GPG private key (not public) in driver config, exported without a passphrase
- Test signing locally with gpg --detach-sign before pasting the key
- Keep the full ARMOR BEGIN/END block intact when copying
When it happens
Trigger: Calling the GitHub driver's release-creation path that signs a commit (MakeDir/commit building for github_releases with a signing key configured). DetachSign is invoked with the entity obtained from the configured private key; any armored-key parse error, missing private key ring, or passphrase-protected key triggers this before armoring begins.
Common situations: User pastes a GPG public key instead of the private key into driver config; key is exported with --armor but has a passphrase; key uses unsupported algorithm (e.g. newer Ed25519 with unsupported subkey packets in older x/crypto/openpgp); whitespace/newline corruption when copying the armored key into the admin UI.
Related errors
- committer email is required
- committer name is required
- author email is required
- author name is required
- cannot download a submodule
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/9891dd85edc6b803.
Report an issue: GitHub.