{"record":{"id":"ffadcc64d869798b","repo":"block/buzz","slug":"sign-kind-39001-e","errorCode":null,"errorMessage":"sign kind:39001: {e}","messagePattern":"sign kind:39001: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/buzz-admin/src/main.rs","lineNumber":749,"sourceCode":"                    .map_err(|e| anyhow::anyhow!(\"sign kind:39000: {e}\"))?;\n                db.replace_addressable_event(tenant.community(), &event, Some(channel.id))\n                    .await?;\n            }\n\n            // kind:39001 — admins\n            {\n                let mut tags: Vec<Tag> = vec![Tag::parse([\"d\", &channel_id_str])?];\n                for m in members\n                    .iter()\n                    .filter(|m| m.role == \"owner\" || m.role == \"admin\")\n                {\n                    let pk = hex::encode(&m.pubkey);\n                    tags.push(Tag::parse([\"p\", &pk, &m.role])?);\n                }\n                let event = EventBuilder::new(Kind::Custom(KIND_NIP29_GROUP_ADMINS as u16), \"\")\n                    .tags(tags)\n                    .sign_with_keys(&relay_keys)\n                    .map_err(|e| anyhow::anyhow!(\"sign kind:39001: {e}\"))?;\n                db.replace_addressable_event(tenant.community(), &event, Some(channel.id))\n                    .await?;\n            }\n        }\n\n        // kind:39002 — members\n        {\n            let mut tags: Vec<Tag> = vec![Tag::parse([\"d\", &channel_id_str])?];\n            for m in &members {\n                let pk = hex::encode(&m.pubkey);\n                tags.push(Tag::parse([\"p\", &pk, \"\", &m.role])?);\n            }\n            let event = EventBuilder::new(Kind::Custom(39002), \"\")\n                .tags(tags)\n                .sign_with_keys(&relay_keys)\n                .map_err(|e| anyhow::anyhow!(\"sign kind:39002: {e}\"))?;\n            db.replace_addressable_event(tenant.community(), &event, Some(channel.id))\n                .await?;","sourceCodeStart":731,"sourceCodeEnd":767,"githubUrl":"https://github.com/block/buzz/blob/ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be/crates/buzz-admin/src/main.rs#L731-L767","documentation":"reconcile-channels builds the kind:39001 (KIND_NIP29_GROUP_ADMINS) addressable event — a d tag with the channel UUID plus a p tag (pubkey, role) for every member whose role is owner or admin — then signs it with relay_keys. A failure at sign_with_keys is a nostr signing/serialization failure, not a tag-parse failure (those propagate directly from Tag::parse with the tag error).","triggerScenarios":"Signing with key material that cannot produce a signature; a p-tag pubkey that hex-encodes to a value nostr rejects during serialization; relay_keys generated as ephemeral in a previous broken run.","commonSituations":"Member pubkeys stored as raw bytes with invalid length in the DB (hex::encode of a 33-byte value yields 66 chars, which parse rejects or sign chokes on); rotating the relay key between runs.","solutions":["Check the chained {e} for the nostr Error variant.","Validate admin/owner pubkey columns: SELECT pubkey FROM relay_members WHERE role IN ('owner','admin'); — raw-byte length must be 32 (hex-encodes to 64).","Confirm relay_keys came from --relay-key/BUZZ_RELAY_PRIVATE_KEY (the intended stable key), not the ephemeral warning path.","Fix rows or key, then re-run reconcile-channels."],"exampleFix":"-- before: pubkey stored as 33 raw bytes (parity byte kept)\nSELECT octet_length(pubkey) FROM relay_members WHERE role = 'admin'; -- 33\n-- after: strip to the 32-byte x-only form\nUPDATE relay_members SET pubkey = substring(pubkey FROM 2 FOR 32) WHERE octet_length(pubkey) = 33;","handlingStrategy":"validation","validationCode":"-- precheck the pubkeys that feed kind:39001's p tags\nSELECT pubkey, octet_length(pubkey) AS bytes, role\nFROM relay_members WHERE role IN ('owner', 'admin');\n-- every row must show bytes = 32 (hex-encodes to 64 chars); fix any outlier first","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Constrain the column: CHECK (octet_length(pubkey) = 32) on raw-byte pubkey columns (or CHAR(64) hex form).","Audit role values on member insert; only owner/admin rows enter this event.","Run reconcile with a verified key so signing failures localize to data, not key material."],"tags":["buzz-admin","nostr","event-signing","kind-39001","channel-admins"],"backgroundTag":"nostr-event-signing-failed","analyzedSha":"ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be","analyzedAt":"2026-08-20T04:38:24.874Z","contentChangedAt":"2026-08-20T04:38:24.874Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}