{"record":{"id":"eb954f81b121336f","repo":"netbirdio/netbird","slug":"failed-to-parse-root-public-key-s-w","errorCode":null,"errorMessage":"failed to parse root public key(s): %w","messagePattern":"failed to parse root public key\\(s\\): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/artifactsign.go","lineNumber":219,"sourceCode":"\nfunc handleVerifyArtifactKey(cmd *cobra.Command, artifactKeyFile, rootKeyFile, signatureFile, revocationFile string) error {\n\tcmd.Println(\"🔍 Verifying artifact key...\")\n\n\t// Read artifact key data\n\tartifactKeyData, err := os.ReadFile(artifactKeyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read artifact key file: %w\", err)\n\t}\n\n\t// Read root public key(s)\n\trootKeyData, err := os.ReadFile(rootKeyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read root key file: %w\", err)\n\t}\n\n\trootPublicKeys, err := parseRootPublicKeys(rootKeyData)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse root public key(s): %w\", err)\n\t}\n\n\t// Read signature\n\tsigBytes, err := os.ReadFile(signatureFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read signature file: %w\", err)\n\t}\n\n\tsignature, err := reposign.ParseSignature(sigBytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to parse signature: %w\", err)\n\t}\n\n\t// Read optional revocation list\n\tvar revocationList *reposign.RevocationList\n\tif revocationFile != \"\" {\n\t\trevData, err := os.ReadFile(revocationFile)\n\t\tif err != nil {","sourceCodeStart":201,"sourceCodeEnd":237,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactsign.go#L201-L237","documentation":"parseRootPublicKeys failed: it calls reposign.ParseRootPublicKey, which requires a PEM block of type \"ROOT PUBLIC KEY\" with a JSON body and a 32-byte Ed25519 key (reposign/root.go:41-47, key.go:99-124). Wrong tag (most commonly an ARTIFACT PUBLIC KEY passed to --root-key-file), bad PEM, corrupt JSON, or wrong key length fails. Note the helper parses only the first block despite the plural \"key(s)\" in the message (artifactsign.go:270-276).","triggerScenarios":"Passing the artifact public key bundle to --root-key-file; passing a root private key; a standard PEM public key; first block of a concatenated root key bundle being corrupt.","commonSituations":"Two key files with similar names in the release directory; rotating root keys and grabbing the wrong generation; using openssl-generated keys outside the signer toolchain.","solutions":["Pass the ROOT PUBLIC KEY PEM produced by `signer generate-root-key`: head -1 must read -----BEGIN ROOT PUBLIC KEY-----","Confirm you did not swap --root-key-file and --artifact-key-file","If using concatenated root keys, ensure the first PEM block is intact and correctly tagged"],"exampleFix":"// before\n./signer verify-artifact-key --root-key-file artifact-key-pub.pem ...\n\n// after\n./signer verify-artifact-key --root-key-file root-key-pub.pem ...","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isRootPublicKeyPEM(data []byte) bool {\n    block, _ := pem.Decode(data)\n    return block != nil && block.Type == \"ROOT PUBLIC KEY\"\n}","tryCatchPattern":null,"preventionTips":["Check the PEM tag line before passing a file as --root-key-file","Keep artifact public keys and root public keys in separately named directories"],"tags":["go","crypto","ed25519","pem","release-signing"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}