{"record":{"id":"eabb98f35257bdb8","repo":"netbirdio/netbird","slug":"failed-to-parse-revocation-list-w","errorCode":null,"errorMessage":"failed to parse revocation list: %w","messagePattern":"failed to parse revocation list: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/signer/artifactsign.go","lineNumber":243,"sourceCode":"\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 {\n\t\t\treturn fmt.Errorf(\"read revocation file: %w\", err)\n\t\t}\n\n\t\trevocationList, err = reposign.ParseRevocationList(revData)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to parse revocation list: %w\", err)\n\t\t}\n\t}\n\n\t// Validate artifact key(s)\n\tvalidKeys, err := reposign.ValidateArtifactKeys(rootPublicKeys, artifactKeyData, *signature, revocationList)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"artifact key verification failed: %w\", err)\n\t}\n\n\tcmd.Println(\"✅ Artifact key(s) verified successfully\")\n\tcmd.Printf(\"Signed by root key: %s\\n\", signature.KeyID)\n\tcmd.Printf(\"Signature timestamp: %s\\n\", signature.Timestamp.Format(\"2006-01-02 15:04:05 MST\"))\n\tcmd.Printf(\"\\nValid artifact keys (%d):\\n\", len(validKeys))\n\tfor i, key := range validKeys {\n\t\tcmd.Printf(\"  [%d] Key ID: %s\\n\", i+1, key.Metadata.ID)\n\t\tcmd.Printf(\"      Created: %s\\n\", key.Metadata.CreatedAt.Format(\"2006-01-02 15:04:05 MST\"))\n\t\tif !key.Metadata.ExpiresAt.IsZero() {\n\t\t\tcmd.Printf(\"      Expires: %s\\n\", key.Metadata.ExpiresAt.Format(\"2006-01-02 15:04:05 MST\"))","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/signer/artifactsign.go#L225-L261","documentation":"reposign.ParseRevocationList failed on the optional revocation file. Beyond JSON unmarshalling, it enforces that last_updated and expires_at are present and non-zero, and that every key in the revoked map is a valid 16-hex-char KeyID (reposign/revocation.go:39-87). A missing field, a hand-edited key ID, or passing the .sig file fails.","triggerScenarios":"Hand-written or trimmed revocation JSON missing expires_at or last_updated; a revoked map key that is not 16 hex chars; passing revocation-list.json.sig to --revocation-file; malformed JSON from a partial download.","commonSituations":"Ops edits the revocation list directly instead of using create/extend-revocation-list; the .sig and the list get swapped in scripts.","solutions":["Validate shape: jq '.revoked, .last_updated, .expires_at' <file> must all be present, and revoked keys must be 16-char hex strings","Only produce lists via `signer create-revocation-list` / `signer extend-revocation-list`","Confirm you passed the list JSON, not its .sig","Re-download the file if the download may be truncated"],"exampleFix":"// before (hand-edited list missing expires_at)\n{\"revoked\":{\"deadbeefdeadbeef\":\"2026-01-01T00:00:00Z\"}}\n\n// after (created by the signer, all fields present)\n./signer create-revocation-list --revocation-list-file revocation-list.json --private-root-key root-key.pem","handlingStrategy":"validation","validationCode":"var probe struct {\n    Revoked     map[string]time.Time `json:\"revoked\"`\n    LastUpdated time.Time            `json:\"last_updated\"`\n    ExpiresAt   time.Time            `json:\"expires_at\"`\n}\nif err := json.Unmarshal(revData, &probe); err != nil || probe.LastUpdated.IsZero() || probe.ExpiresAt.IsZero() {\n    log.Fatalf(\"revocation list malformed: %v\", err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Create and modify revocation lists only via create-revocation-list / extend-revocation-list","Never hand-edit the JSON; missing last_updated or expires_at hard-fails parsing"],"tags":["go","json","release-signing","validation"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}