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 nil

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. ls -l the exact --private-root-key value and fix the path
  2. Mount/provision the private root key from the vault before running the command
  3. Run as the user that owns the key file or fix its permissions
  4. 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

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


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