netbirdio/netbird · error

read root private key file: %w

Error message

read root private key file: %w

What it means

os.ReadFile on the --root-private-key-file path failed inside handleCreateArtifactKey, before any cryptographic work. The wrapped error is a standard *fs.PathError: 'no such file or directory', 'permission denied', or 'is a directory'.

Source

Thrown at client/cmd/signer/artifactkey.go:102

	bundlePubKeysCmd.Flags().StringVar(&bundlePubKeysFile, "bundle-pub-key-file", "", "Path where the public keys will be saved")

	if err := bundlePubKeysCmd.MarkFlagRequired("root-private-key-file"); err != nil {
		panic(fmt.Errorf("mark root-private-key-file as required: %w", err))
	}
	if err := bundlePubKeysCmd.MarkFlagRequired("artifact-pub-key-file"); err != nil {
		panic(fmt.Errorf("mark artifact-pub-key-file as required: %w", err))
	}
	if err := bundlePubKeysCmd.MarkFlagRequired("bundle-pub-key-file"); err != nil {
		panic(fmt.Errorf("mark bundle-pub-key-file as required: %w", err))
	}
}

func handleCreateArtifactKey(cmd *cobra.Command, rootPrivKeyFile, artifactPrivKeyFile, artifactPubKeyFile string, expiration time.Duration) error {
	cmd.Println("Creating new artifact signing key...")

	privKeyPEM, err := os.ReadFile(rootPrivKeyFile)
	if err != nil {
		return fmt.Errorf("read root private key file: %w", err)
	}

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

	artifactKey, privPEM, pubPEM, signature, err := reposign.GenerateArtifactKey(privateRootKey, expiration)
	if err != nil {
		return fmt.Errorf("generate artifact key: %w", err)
	}

	if err := os.WriteFile(artifactPrivKeyFile, privPEM, 0o600); err != nil {
		return fmt.Errorf("write private key file (%s): %w", artifactPrivKeyFile, err)
	}

	if err := os.WriteFile(artifactPubKeyFile, pubPEM, 0o600); err != nil {
		return fmt.Errorf("write public key file (%s): %w", artifactPubKeyFile, err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Check the exact path and rerun with an absolute path to rule out working-directory issues
  2. Confirm the file exists and is readable (ls -l, or run as the owning user)
  3. If no root key exists yet, generate one with the create-root-key command first

Example fix

// before
create-artifact-key --root-private-key-file root.key ...
// after
create-artifact-key --root-private-key-file /etc/netbird/signing/root.key ...
Defensive patterns

Strategy: validation

Validate before calling

keyPath := "/etc/netbird/signing/root.key"
if _, err := os.Stat(keyPath); err != nil {
    log.Fatalf("root key not available at %s: %v", keyPath, err)
}
// then invoke create-artifact-key with keyPath

Prevention

When it happens

Trigger: create-artifact-key invoked with a --root-private-key-file path that does not exist, is a directory, or is not readable by the current user (e.g. root-owned 0600 file read as a normal user).

Common situations: Typo in the path; running from a different working directory with a relative path; the root key was never generated or was moved; file permissions were tightened after generation.

Related errors


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