netbirdio/netbird · error
failed to read private root key file: %w
Error message
failed to read private root key file: %w
What it means
os.ReadFile on the --private-root-key path failed in `signer create-revocation-list`. This flag must point at the ROOT PRIVATE KEY PEM. Wrapped *fs.PathError causes: missing file, permission denied, or directory. Because the private root key is highly sensitive, it is often stored in a vault or restricted path, which makes permission errors common.
Source
Thrown at client/cmd/signer/revocation.go:99
verifyRevocationListCmd.Flags().StringVar(&revocationListFile, "revocation-list-file", "", "Path to the revocation list file")
verifyRevocationListCmd.Flags().StringVar(&signatureFile, "signature-file", "", "Path to the signature file")
verifyRevocationListCmd.Flags().StringVar(&publicRootKeyFile, "public-root-key", "", "Path to the public root key PEM file")
if err := verifyRevocationListCmd.MarkFlagRequired("revocation-list-file"); err != nil {
panic(err)
}
if err := verifyRevocationListCmd.MarkFlagRequired("signature-file"); err != nil {
panic(err)
}
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 nilView on GitHub (pinned to 93e97f4bf1)
Solutions
- ls -l the exact --private-root-key value and fix the path
- Mount/provision the private root key from the vault before running the command
- Run as the user that owns the key file or fix its permissions
- If only the public key exists locally, obtain the private key from the key custodian
Example fix
// before
return fmt.Errorf("failed to read private root key file: %w", err)
// after
return fmt.Errorf("failed to read private root key file %s: %w", privateRootKeyFile, err) Defensive patterns
Strategy: validation
Validate before calling
if info, err := os.Stat(privateRootKeyFile); err != nil || info.IsDir() {
log.Fatalf("private root key %s not readable: %v", privateRootKeyFile, err)
} Prevention
- Mount the private root key from the secret store at a fixed absolute path in CI
- Restrict operations requiring the private root key to a dedicated, audited pipeline job
When it happens
Trigger: Private root key not mounted from the secret store in CI; path typo; the operator only has the public root key locally; file mode 0600 owned by another user.
Common situations: See trigger scenarios.
Related errors
- read artifact file: %w
- write signature file (%s): %w
- read public key file: %w
- read signature file: %w
- read artifact key file: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/dde055976645959b.
Report an issue: GitHub.