{"record":{"id":"579ffc88930ff6ed","repo":"block/buzz","slug":"delete-requires-target-event-id","errorCode":null,"errorMessage":"delete requires target_event_id","messagePattern":"delete requires target_event_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/buzz-relay/src/handlers/report_resolution.rs","lineNumber":752,"sourceCode":"                    ctx.community_id,\n                    ch,\n                    target,\n                    ctx.actor_pubkey,\n                )\n                .await\n                .map_err(|e| anyhow::anyhow!(\"kick failed: {e}\"))?\n            {\n                buzz_db::relay_admin_actions::KickWithMarkerResult::Removed => Ok(true),\n                buzz_db::relay_admin_actions::KickWithMarkerResult::AlreadyMarked => Ok(false),\n                buzz_db::relay_admin_actions::KickWithMarkerResult::AlreadyGone => Err(\n                    anyhow::anyhow!(\"kick target was already absent before this action\"),\n                ),\n            }\n        }\n        \"delete\" => {\n            let target = ctx\n                .target_event_id\n                .ok_or_else(|| anyhow::anyhow!(\"delete requires target_event_id\"))?;\n            let meta = state\n                .db\n                .get_thread_metadata_by_event(ctx.community_id, target)\n                .await\n                .map_err(|e| anyhow::anyhow!(\"thread metadata lookup failed: {e}\"))?;\n            let parent_id = meta.as_ref().and_then(|m| m.parent_event_id.clone());\n            let root_id = meta.as_ref().and_then(|m| m.root_event_id.clone());\n            state\n                .db\n                .execute_delete_with_marker(\n                    action_id,\n                    lease_token,\n                    ctx.community_id,\n                    target,\n                    parent_id.as_deref(),\n                    root_id.as_deref(),\n                )\n                .await","sourceCodeStart":734,"sourceCodeEnd":770,"githubUrl":"https://github.com/block/buzz/blob/eed74bde2f4797714335ac10c56c0b0244c1def4/crates/buzz-relay/src/handlers/report_resolution.rs#L734-L770","documentation":"`run_atomic_mutation` was asked to execute a \"delete\" enforcement action, but `EnforcementCtx.target_event_id` was `None`. Deleting a reported event requires its id; the handler cannot proceed. Like the kick/timeout variants, this is an internal invariant failure indicating the enforcement-context builder failed to decode or attach the report's event target.","triggerScenarios":"1) The report targeted a pubkey (user-level report) but was resolved with a \"delete\" action instead. 2) The report target hex failed to decode to a valid event id upstream and was left as `None`. 3) A custom or hand-rolled `EnforcementCtx` for delete omitted `target_event_id`. 4) Legacy admin-action rows whose stored report target predates event-id scoping.","commonSituations":"Operator UIs letting admins pick \"delete\" on a user-level report; corrupt or partially-written report target columns; forks or scripts inserting recovery actions with the wrong target kind; report kind registry changes leaving old rows un-decodable.","solutions":["Verify the resolution action matches the report's target kind: only resolve event-kind reports (target decode yields an event id) with \"delete\".","Check the report row's stored target (kind + hex) — re-trigger resolution after fixing the target, or resolve with \"ban\"/\"kick\" instead.","If building contexts in code/tests, populate `target_event_id` from the decoded report target before calling `drive_enforcement`.","Add early validation in the resolve endpoint that rejects delete-on-pubkey reports with a client-facing error rather than this internal one."],"exampleFix":"// before\nlet ctx = EnforcementCtx { action: \"delete\", target_event_id: None, ..base };\n// after\nlet target_event_id = report.target_event_id\n    .ok_or_else(|| anyhow::anyhow!(\"cannot delete: report target is not an event\"))?;\nlet ctx = EnforcementCtx { action: \"delete\", target_event_id: Some(target_event_id), ..base };","handlingStrategy":"validation","validationCode":"fn ensure_delete_ctx(ctx: &EnforcementCtx) -> anyhow::Result<&EnforcementCtx<'_>> {\n    anyhow::ensure!(ctx.action != \"delete\" || ctx.target_event_id.is_some(),\n        \"delete enforcement requires target_event_id; report target must be an event\");\n    Ok(ctx)\n}\n// call before drive_enforcement:\n// ensure_delete_ctx(&ctx)?;","typeGuard":"fn delete_ctx_is_complete(ctx: &EnforcementCtx<'_>) -> bool {\n    ctx.action != \"delete\" || ctx.target_event_id.is_some()\n}","tryCatchPattern":"match run_atomic_mutation(state, action_id, lease_token, &ctx).await {\n    Err(e) if e.to_string().contains(\"delete requires target_event_id\") => {\n        mark_action_failed(action_id, \"report target is not an event; delete impossible\".into());\n    }\n    other => other?,\n}","preventionTips":["Only expose \"delete\" as a resolution option on event-kind reports.","Validate the report target decodes to an event id before persisting a delete action.","Keep one code path (derive_enforcement_target_pub) populating target fields.","Reject delete-on-pubkey resolutions at the API boundary with a client-facing error."],"tags":["enforcement","missing-context","internal-invariant","report-resolution"],"backgroundTag":"missing-enforcement-target","analyzedSha":"eed74bde2f4797714335ac10c56c0b0244c1def4","analyzedAt":"2026-08-30T13:49:18.474Z","contentChangedAt":"2026-08-30T13:49:18.474Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}