{"record":{"id":"03915acf95d4b7e0","repo":"block/buzz","slug":"failed-to-sign-kind-13534-e","errorCode":null,"errorMessage":"failed to sign kind:13534: {e}","messagePattern":"failed to sign kind:13534: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/buzz-admin/src/main.rs","lineNumber":374,"sourceCode":"    };\n\n    let members = db.list_relay_members(tenant.community()).await?;\n\n    let mut tags: Vec<Tag> = Vec::with_capacity(members.len() + 1);\n    // NIP-70 protected-event marker — prevents re-broadcasting by third parties.\n    tags.push(Tag::parse([\"-\"]).map_err(|e| anyhow::anyhow!(\"failed to build '-' tag: {e}\"))?);\n    for member in &members {\n        tags.push(\n            Tag::parse([\"member\", &member.pubkey, &member.role])\n                .map_err(|e| anyhow::anyhow!(\"failed to build member tag: {e}\"))?,\n        );\n    }\n\n    let event = EventBuilder::new(Kind::Custom(KIND_NIP43_MEMBERSHIP_LIST as u16), \"\")\n        .tags(tags)\n        .custom_created_at(nostr::Timestamp::from(ts))\n        .sign_with_keys(relay_keypair)\n        .map_err(|e| anyhow::anyhow!(\"failed to sign kind:13534: {e}\"))?;\n\n    let (stored, was_inserted) = db\n        .replace_addressable_event(tenant.community(), &event, None)\n        .await?;\n    if was_inserted {\n        // Publish to Redis so live clients receive the updated roster.\n        // Community-global scope (EventTopic::Global) matches the relay's own\n        // membership-list publish path; the tenant fixes the community.\n        if let Err(e) = pubsub\n            .publish_event(tenant, EventTopic::Global, &stored.event)\n            .await\n        {\n            warn!(\"Redis publish of kind:13534 failed: {e}\");\n        }\n    }\n\n    tracing::info!(\n        member_count = members.len(),","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/crates/buzz-admin/src/main.rs#L356-L392","documentation":"After the member tags are assembled, buzz-admin signs the kind:13534 membership-list event with the relay keypair via EventBuilder::sign_with_keys. Signing fails if the nostr crate cannot serialize the event — a tag that fails standardization, or a custom_created_at outside the accepted u64-seconds range — or if the keypair itself is unusable. Note the timestamp is computed as (existing + 1).max(now); a garbage stored created_at (e.g., milliseconds instead of seconds) overflows on the +1.","triggerScenarios":"The previous kind:13534 row's created_at was stored in milliseconds (1.7e12) so existing+1 leaves the valid seconds range; or the BUZZ_RELAY_PRIVATE_KEY parsed into a Keys object that cannot sign (wrong-length material); or one of the member tags serializes to an invalid form.","commonSituations":"Migrating timestamps between ms and s conventions; switching the relay key without updating the CLI env; a hand-edited membership event row.","solutions":["Read the chained {e} from the message first — it names the exact nostr Error variant (timestamp, key, or tag).","Check the stored timestamp: SELECT created_at FROM events WHERE kind = 13534; — it must be Unix seconds, not milliseconds; fix the row.","Confirm BUZZ_RELAY_PRIVATE_KEY is the relay's 32-byte hex or nsec secret (not the public key) with no whitespace or quotes.","Re-run add-member/remove-member to rebuild and republish the list."],"exampleFix":"-- before: created_at stored in milliseconds\nSELECT created_at FROM events WHERE kind = 13534; -- 1737000000000\n-- after: seconds\nUPDATE events SET created_at = created_at / 1000 WHERE kind = 13534 AND created_at > 100000000000;","handlingStrategy":"validation","validationCode":"-- before republishing kind:13534, confirm the previous created_at is sane Unix seconds\nSELECT created_at FROM events WHERE kind = 13534;\n-- valid seconds are < 10^11; anything ~1.7e12 is milliseconds and must be fixed","typeGuard":null,"tryCatchPattern":"match run_publish_membership(...).await {\n    Ok(_) => {},\n    Err(e) if e.to_string().contains(\"failed to sign kind:13534\") => {\n        // inspect e.source() chain for the nostr Error variant before retrying;\n        // do not blind-retry: signing failures are deterministic\n        log_and_alert(&e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Store nostr created_at values in seconds only; enforce with a CHECK (created_at < 100000000000) on event tables.","Smoke-test the relay key by signing a scratch event before running roster mutations.","Never run admin mutations with a key you have not already used successfully for signing."],"tags":["buzz-admin","nostr","event-signing","kind-13534","timestamps"],"backgroundTag":"nostr-event-signing-failed","analyzedSha":"dad5a33865fc81a2e55b3b60746632f615ec1e3a","analyzedAt":"2026-08-20T04:38:24.874Z","contentChangedAt":"2026-08-20T04:38:24.874Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}