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

  1. Re-export the private key without a passphrase: gpg --export-secret-keys --armor KEYID and paste the full ARMORED block including headers
  2. Verify the key parses standalone: gpg --list-packets key.asc or try signing with gpg --detach-sign locally
  3. 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
  4. 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

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


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/9891dd85edc6b803. Report an issue: GitHub.