{"record":{"id":"8404e70eafa32d58","repo":"block/buzz","slug":"invalid-a-tag-format","errorCode":null,"errorMessage":"invalid a-tag format","messagePattern":"invalid a-tag format","errorType":"validation","errorClass":"IngestError::Rejected","httpStatus":null,"severity":"error","filePath":"crates/buzz-relay/src/handlers/side_effects.rs","lineNumber":243,"sourceCode":"pub async fn validate_standard_deletion_event(\n    tenant: &TenantContext,\n    event: &Event,\n    state: &Arc<AppState>,\n) -> anyhow::Result<()> {\n    let actor_bytes = effective_message_author(event, &state.relay_keypair.public_key());\n    let target_ids = extract_target_event_ids(event);\n\n    if !has_e_tag(event) {\n        // a-tag deletion: verify author owns the addressable event\n        let a_tag = event\n            .tags\n            .iter()\n            .find(|t| t.kind().to_string() == \"a\")\n            .and_then(|t| t.content().map(|s| s.to_string()))\n            .ok_or_else(|| anyhow::anyhow!(\"missing e or a tag for target\"))?;\n        let parts: Vec<&str> = a_tag.splitn(3, ':').collect();\n        if parts.len() < 2 {\n            return Err(anyhow::anyhow!(\"invalid a-tag format\"));\n        }\n        let target_pubkey_bytes =\n            hex::decode(parts[1]).map_err(|_| anyhow::anyhow!(\"invalid pubkey in a-tag\"))?;\n        if target_pubkey_bytes != actor_bytes\n            && !state\n                .db\n                .is_agent_owner(tenant.community(), &target_pubkey_bytes, &actor_bytes)\n                .await?\n        {\n            return Err(anyhow::anyhow!(\"must be event author\"));\n        }\n        return Ok(());\n    }\n\n    for target_id in target_ids {\n        let target_event = state\n            .db\n            .get_event_by_id_including_deleted(tenant.community(), &target_id)","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/block/buzz/blob/f956e6fe06a76e50cbd8fba1a162482e752e7f1a/crates/buzz-relay/src/handlers/side_effects.rs#L225-L261","documentation":"The kind:5 deletion carried an 'a' tag (and no 'e' tag), but splitting its value on ':' with splitn(3, ':') produced fewer than 2 segments — i.e. the coordinate is missing the kind:pubkey separator. A NIP-01 'a' coordinate must be \"<kind>:<pubkey-hex>:<d-identifier>\", and the relay needs at least kind and pubkey segments to authorize the deletion.","triggerScenarios":"a tag value like \"30078\" (kind only, no colon), \"\" (empty string), or \"chat/topic\" (non-coordinate content); a client concatenating the coordinate with a separator other than ':'; template string interpolation that drops the pubkey segment.","commonSituations":"Building the a tag from a struct with a buggy Display impl; copying a d-tag identifier into the a tag position; locale-specific separators introduced by string tooling.","solutions":["Format the a tag as \"<kind>:<64-hex pubkey>:<d-value>\", e.g. \"30078:<pubkey>:general\"","Assert the coordinate has >= 2 colon-separated parts before publishing (a cheap client-side splitn(3,':') check)","If you meant to delete a concrete event rather than an addressable one, use an e tag with the 32-byte event id instead"],"exampleFix":"// before\nTag::custom(TagKind::Custom(\"a\"), vec![format!(\"{}\", kind)]) // \"30078\" → invalid a-tag format\n\n// after\nTag::custom(\n    TagKind::Custom(\"a\"),\n    vec![format!(\"{}:{}:{}\", kind, pubkey_hex, d_identifier)],\n)","handlingStrategy":"validation","validationCode":"// Validate the coordinate shape before publishing\nfn valid_a_tag(value: &str) -> bool {\n    let parts: Vec<&str> = value.splitn(3, ':').collect();\n    parts.len() >= 2 && !parts[0].is_empty() && !parts[1].is_empty()\n}\nlet a = format!(\"{}:{}:{}\", kind, pubkey_hex, d);\nassert!(valid_a_tag(&a));","typeGuard":"function isValidCoordinate(v: string): boolean {\n  const parts = v.split(\":\");\n  return parts.length >= 2 && parts[0] !== \"\" && /^[0-9a-f]{64}$/.test(parts[1]);\n}","tryCatchPattern":"if let Err(e) = validate_standard_deletion_event(&tenant, &event, &state).await {\n    if e.to_string().contains(\"invalid a-tag format\") {\n        return reject(\"a tag must be kind:pubkey:d-identifier\", &event.id);\n    }\n    return Err(e);\n}","preventionTips":["Never string-build coordinates by hand; use an SDK Coordinate type","Check the template has all three placeholders before format!() — a missing segment drops the colon","Round-trip parse the coordinate client-side with splitn(3, ':') exactly like the relay does"],"tags":["nostr","nip-09","deletion","a-tag","validation"],"backgroundTag":"nip09-malformed-a-tag","analyzedSha":"f956e6fe06a76e50cbd8fba1a162482e752e7f1a","analyzedAt":"2026-08-16T22:11:40.750Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}