{"record":{"id":"e91dbe4a1d0c2d03","repo":"block/buzz","slug":"thread-metadata-lookup-failed-e","errorCode":null,"errorMessage":"thread metadata lookup failed: {e}","messagePattern":"thread metadata lookup failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/buzz-relay/src/handlers/report_resolution.rs","lineNumber":757,"sourceCode":"                .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\n                .map_err(|e| anyhow::anyhow!(\"delete failed: {e}\"))\n        }\n        other => Err(anyhow::anyhow!(\"unexpected enforcement action: {other}\")),\n    };\n","sourceCodeStart":739,"sourceCodeEnd":775,"githubUrl":"https://github.com/block/buzz/blob/eed74bde2f4797714335ac10c56c0b0244c1def4/crates/buzz-relay/src/handlers/report_resolution.rs#L739-L775","documentation":"Before deleting the target event, `run_atomic_mutation` calls `get_thread_metadata_by_event` to look up the thread's parent/root ids (used to update thread counters), and that query failed with a database error, wrapped as `thread metadata lookup failed: {e}`. This is a DB-layer failure, not a business-logic rejection — the delete itself never ran.","triggerScenarios":"1) Postgres connection failure, pool exhaustion, or statement timeout while reading thread metadata. 2) Schema drift: the thread-metadata table/columns expected by the query are missing (failed migration). 3) Malformed `target_event_id` causing a query/decode error at the DB layer rather than a clean `None`.","commonSituations":"Relay under heavy load with a saturated connection pool; a half-applied migration after upgrading the relay binary; disk/network issues between relay and Postgres in containerized deployments (e.g. the staging Kubernetes setup).","solutions":["Read the wrapped `{e}` in relay logs to identify the exact Postgres error (connection, timeout, relation-not-found).","For relation/column errors: run pending migrations and restart the relay so schema matches the binary.","For timeouts/pool exhaustion: raise pool size or statement timeout, and retry — enforcement is idempotent and re-drivable.","Confirm the event id passed to `get_thread_metadata_by_event` is well-formed (32-byte binary) and not truncated upstream."],"exampleFix":"// before\nlet meta = state.db.get_thread_metadata_by_event(ctx.community_id, target)\n    .await\n    .map_err(|e| anyhow::anyhow!(\"thread metadata lookup failed: {e}\"))?;\n// after\nlet meta = match state.db.get_thread_metadata_by_event(ctx.community_id, target).await {\n    Ok(m) => m,\n    Err(e) if is_transient(&e) => {\n        tokio::time::sleep(Duration::from_millis(200)).await;\n        state.db.get_thread_metadata_by_event(ctx.community_id, target).await\n            .map_err(|e| anyhow::anyhow!(\"thread metadata lookup failed: {e}\"))?\n    }\n    Err(e) => return Err(anyhow::anyhow!(\"thread metadata lookup failed: {e}\")),\n};","handlingStrategy":"retry","validationCode":"// verify the target event exists before driving a delete\nlet exists = state.db.event_exists(community_id, target_event_id).await?;\nanyhow::ensure!(exists, \"target event not found in community; skip delete\");","typeGuard":"fn is_transient_db_err(e: &anyhow::Error) -> bool {\n    let s = e.to_string();\n    s.contains(\"connection\") || s.contains(\"timeout\") || s.contains(\"pool\")\n}","tryCatchPattern":"match run_atomic_mutation(state, action_id, lease_token, &ctx).await {\n    Err(e) if is_transient_db_err(&e) => schedule_retry(action_id, backoff()),\n    Err(e) if e.to_string().contains(\"thread metadata lookup failed\") => {\n        alert_schema_drift_or_db_health(action_id, e);\n    }\n    other => other?,\n}","preventionTips":["Run `just test` (Postgres-backed) after touching buzz-db or migration files.","Confirm migrations are applied whenever the relay binary is upgraded.","Monitor Postgres health (pool saturation, statement timeouts) around enforcement workers.","Log the wrapped inner DB error verbatim — the message alone hides the root cause."],"tags":["postgres","database","enforcement","transient"],"backgroundTag":"database-transaction-failed","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"}