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
- Read the wrapped %w error to identify which internal step failed (failed to sign / failed to marshal revocation list / failed to marshal signature)
- Re-run the command once to rule out a transient runtime fault
- If reproducible, diff client/internal/updater/reposign/revocation.go against upstream and revert custom field changes to RevocationList or Signature
- 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
- Treat any failure from CreateRevocationList after a successful ParseRootKey as a code defect, not a config issue
- Keep reposign unmodified or regression-test custom RevocationList/Signature fields with json.Marshal in unit tests
- Log the wrapped chain verbatim so the failing marshal step is identifiable
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
- failed to extend revocation list: %w
- failed to parse revocation list: %w
- failed to parse signature: %w
- failed to write output files: %w
- failed to read revocation list file: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/d810149353e0f235.
Report an issue: GitHub.