{"record":{"id":"07415da1f7ed2ff2","repo":"netbirdio/netbird","slug":"failed-to-read-signature-file-w","errorCode":null,"errorMessage":"failed to read signature file: %w","messagePattern":"failed to read signature file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/revocation.go","lineNumber":169,"sourceCode":"\tif err := writeOutputFiles(revocationListFile, revocationListFile+\".sig\", newRLBytes, sigBytes); err != nil {\n\t\treturn fmt.Errorf(\"failed to write output files: %w\", err)\n\t}\n\n\tcmd.Println(\"✅ Revocation list extended successfully\")\n\treturn nil\n}\n\nfunc handleVerifyRevocationList(cmd *cobra.Command, revocationListFile, signatureFile, publicRootKeyFile string) error {\n\t// Read revocation list file\n\trlBytes, err := os.ReadFile(revocationListFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read revocation list file: %w\", err)\n\t}\n\n\t// Read signature file\n\tsigBytes, err := os.ReadFile(signatureFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read signature file: %w\", err)\n\t}\n\n\t// Read public root key file\n\tpubKeyPEM, err := os.ReadFile(publicRootKeyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read public root key file: %w\", err)\n\t}\n\n\t// Parse public root key\n\tpublicKey, err := reposign.ParseRootPublicKey(pubKeyPEM)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse public root key: %w\", err)\n\t}\n\n\t// Parse signature\n\tsignature, err := reposign.ParseSignature(sigBytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse signature: %w\", err)","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/revocation.go#L151-L187","documentation":"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.","triggerScenarios":"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.","commonSituations":"Artifact pipelines that publish the list but drop unknown *.sig files; operators renaming files for distribution; the .sig never committed because .gitignore excluded it.","solutions":["Fetch the matching .sig — it is written beside the list as <revocation-list-file>.sig at sign time","Check for a rename: ls <dir> to see whether the signature survived under another name","If the .sig is lost, regenerate the pair by re-running extend-revocation-list with the same key and list, then republish both","Verify both files come from the same signing run — mixing list revisions with old signatures fails validation"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"sigPath := revocationListFile + \".sig\"\nif _, err := os.Stat(sigPath); err != nil {\n    // signature companion missing: regenerate the pair with extend before verifying\n    log.Fatalf(\"signature %s missing: %v\", sigPath, err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat <list>.sig as part of the list artifact, never as a separate file","Exclude *.sig from cleanup rules and gitignore exceptions","Regenerate both files together whenever either is lost"],"tags":["go","cli","file-io","signature","revocation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}