netbirdio/netbird · error

failed to read signature file: %w

Error message

failed to read signature file: %w

What it means

os.ReadFile on the --signature-file path failed in verify-revocation-list. The signature is a separate JSON file (a Signature bundle: base64 signature bytes, timestamp, key_id, algorithm, hash_algo) that create-revocation-list and extend-revocation-list write next to the list as <list-path>.sig; verification needs both files from the same run.

Source

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

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

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

func handleVerifyRevocationList(cmd *cobra.Command, revocationListFile, signatureFile, publicRootKeyFile string) error {
	// Read revocation list file
	rlBytes, err := os.ReadFile(revocationListFile)
	if err != nil {
		return fmt.Errorf("failed to read revocation list file: %w", err)
	}

	// Read signature file
	sigBytes, err := os.ReadFile(signatureFile)
	if err != nil {
		return fmt.Errorf("failed to read signature file: %w", err)
	}

	// Read public root key file
	pubKeyPEM, err := os.ReadFile(publicRootKeyFile)
	if err != nil {
		return fmt.Errorf("failed to read public root key file: %w", err)
	}

	// Parse public root key
	publicKey, err := reposign.ParseRootPublicKey(pubKeyPEM)
	if err != nil {
		return fmt.Errorf("failed to parse public root key: %w", err)
	}

	// Parse signature
	signature, err := reposign.ParseSignature(sigBytes)
	if err != nil {
		return fmt.Errorf("failed to parse signature: %w", err)

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Fetch the matching .sig — it is written beside the list as <revocation-list-file>.sig at sign time
  2. Check for a rename: ls <dir> to see whether the signature survived under another name
  3. If the .sig is lost, regenerate the pair by re-running extend-revocation-list with the same key and list, then republish both
  4. Verify both files come from the same signing run — mixing list revisions with old signatures fails validation
Defensive patterns

Strategy: validation

Validate before calling

sigPath := revocationListFile + ".sig"
if _, err := os.Stat(sigPath); err != nil {
    // signature companion missing: regenerate the pair with extend before verifying
    log.Fatalf("signature %s missing: %v", sigPath, err)
}

Prevention

When it happens

Trigger: Verifying with only the list copied over while the .sig companion was left behind; passing the list path where the signature path is expected but with a typo in the .sig suffix; the .sig deleted by cleanup scripts that treat it as an unknown artifact.

Common situations: Artifact pipelines that publish the list but drop unknown *.sig files; operators renaming files for distribution; the .sig never committed because .gitignore excluded it.

Related errors


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