netbirdio/netbird · error

failed to create revocation list: %w

Error message

failed to create revocation list: %w

What it means

Returned by the create-revocation-list command when reposign.CreateRevocationList fails (client/internal/updater/reposign/revocation.go:155). That function builds an empty RevocationList, signs it with the already-parsed Ed25519 root key, then json.Marshal's the list and the Signature bundle. Every input has been validated by ParseRootKey at this point, and Go's encoder always handles time.Time and KeyID, so the wrapped marshal/sign errors are internal invariant failures rather than configuration problems.

Source

Thrown at client/cmd/signer/revocation.go:109

	if err := verifyRevocationListCmd.MarkFlagRequired("public-root-key"); err != nil {
		panic(err)
	}
}

func handleCreateRevocationList(cmd *cobra.Command, revocationListFile string, privateRootKeyFile string) error {
	privKeyPEM, err := os.ReadFile(privateRootKeyFile)
	if err != nil {
		return fmt.Errorf("failed to read private root key file: %w", err)
	}

	privateRootKey, err := reposign.ParseRootKey(privKeyPEM)
	if err != nil {
		return fmt.Errorf("failed to parse private root key: %w", err)
	}

	rlBytes, sigBytes, err := reposign.CreateRevocationList(*privateRootKey, expirationDuration)
	if err != nil {
		return fmt.Errorf("failed to create revocation list: %w", err)
	}

	if err := writeOutputFiles(revocationListFile, revocationListFile+".sig", rlBytes, sigBytes); err != nil {
		return fmt.Errorf("failed to write output files: %w", err)
	}

	cmd.Println("✅ Revocation list created successfully")
	return nil
}

func handleExtendRevocationList(cmd *cobra.Command, keyID, revocationListFile, privateRootKeyFile string) error {
	privKeyPEM, err := os.ReadFile(privateRootKeyFile)
	if err != nil {
		return fmt.Errorf("failed to read private root key file: %w", err)
	}

	privateRootKey, err := reposign.ParseRootKey(privKeyPEM)
	if err != nil {

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Read the wrapped %w error to identify which internal step failed (failed to sign / failed to marshal revocation list / failed to marshal signature)
  2. Re-run the command once to rule out a transient runtime fault
  3. If reproducible, diff client/internal/updater/reposign/revocation.go against upstream and revert custom field changes to RevocationList or Signature
  4. Report upstream with the full error chain if unmodified code produces it
Defensive patterns

Strategy: try-catch

Try / catch

if _, _, err := reposign.CreateRevocationList(*privateRootKey, expiration); err != nil {
    // internal invariant failure: log the full chain and abort; do not retry blindly
    return fmt.Errorf("create revocation list: %w", err)
}

Prevention

When it happens

Trigger: Running `signer create-revocation-list` where os.ReadFile and reposign.ParseRootKey both succeeded, but json.Marshal(&rl) or json.Marshal(signature) inside CreateRevocationList returns an error, e.g. after someone forked reposign and added a field json.Marshal cannot encode (func, channel, cyclic pointer).

Common situations: Essentially never fires with stock code. Appears when the reposign package was modified (custom RevocationList/Signature fields) or under runtime-level anomalies; the %w chain names the exact failing step (sign / marshal list / marshal signature).

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/d810149353e0f235. Report an issue: GitHub.