{"record":{"id":"47120656a3e76478","repo":"block/buzz","slug":"repo-announcement-lost-community-serving-lease-e","errorCode":null,"errorMessage":"repo announcement lost community serving lease: {error}","messagePattern":"repo announcement lost community serving lease: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/buzz-relay/src/handlers/side_effects.rs","lineNumber":2686,"sourceCode":"    // and pointer below are external S3 effects, so acquire the durable\n    // serving-write lease immediately before that sequence. Once acquired,\n    // deletion must drain this lease before it can freeze the final object list.\n    let serving_write = buzz_deletion::acquire_serving_write(\n        &state.db,\n        tenant.community(),\n        \"git_repo_announcement\",\n    )\n    .await\n    .map_err(|e| anyhow::anyhow!(\"repo announcement rejected by community deletion fence: {e}\"))?;\n\n    #[cfg(test)]\n    if let Some(gate) = &hooks.post_lease_gate {\n        gate.reached.notify_one();\n        gate.resume.notified().await;\n    }\n\n    if let Err(error) = serving_write.verify().await {\n        return Err(anyhow::anyhow!(\n            \"repo announcement lost community serving lease: {error}\"\n        ));\n    }\n\n    // Establish/confirm the manifest pointer, keeping the invariant\n    // \"repo announced ⟺ pointer exists\" so the read path can rely on\n    // pointer-absent meaning never-announced (keeping `info_refs`'s fail-closed\n    // `Ok(None) → 404` unambiguous). Two distinct cases:\n    //\n    // - Fresh `Reserved` claim → `seed_manifest_pointer` (strict). This creates\n    //   the empty pointer, and correctly *fails* if a non-empty pointer already\n    //   exists for a name we just reserved — that would be a suspicious stale\n    //   pointer from a prior repo lifecycle, not a legitimate re-announce.\n    // - Same-owner `AlreadyOwned` (re-announce) → `ensure_manifest_pointer`\n    //   (tolerant). A non-empty pointer is the *normal* post-push state, so\n    //   re-announce must accept it untouched; only an absent pointer is\n    //   repaired by seeding. Using the strict seed here would wrongly reject\n    //   every re-announce after the first push.","sourceCodeStart":2668,"sourceCodeEnd":2704,"githubUrl":"https://github.com/block/buzz/blob/dad5a33865fc81a2e55b3b60746632f615ec1e3a/crates/buzz-relay/src/handlers/side_effects.rs#L2668-L2704","documentation":"After passing the deletion fence and any test gating, the handler re-verifies the serving lease with serving_write.verify() before performing writes. This error means the lease was invalidated between acquisition and verification — i.e. a community deletion fence closed in the interim, so it is no longer safe to write the repo announcement.","triggerScenarios":"A community deletion starts between acquire_serving_write and the verify() call during handle_git_repo_announcement_inner; long-running pre-lease work (test gates, slow handlers) widens the race window.","commonSituations":"Concurrent operator deletion racing with a burst of repo announcements; slow announcement processing (large tag sets, slow DB) leaving the lease open long enough for a deletion to interleave.","solutions":["Retry the whole announcement from scratch — a fresh acquire_serving_write will now correctly fail-fast or succeed if deletion finished.","Confirm whether the community was deleted; if so, stop publishing announcements to it.","Reduce work performed between lease acquisition and verify by keeping the handler's pre-write steps short.","Check wrapped {error} from verify() to confirm the fence-close cause and timing."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// re-check the lease immediately before each write\nserving_write.verify().await.map_err(|e| anyhow!(\"lease lost pre-write: {e}\"))?;","typeGuard":null,"tryCatchPattern":"if let Err(error) = serving_write.verify().await {\n    tracing::warn!(\"announcement lost lease, retrying: {error}\");\n    return retry_announcement(event, 1).await; // full re-acquire path\n}","preventionTips":["Keep work between lease acquisition and verify minimal to shrink the race window.","Implement one full retry (fresh acquire) for lease-lost errors.","Alert on repeated lease-lost errors — indicates concurrent deletions."],"tags":["concurrency","race-condition","fence","relay"],"backgroundTag":"lost-serving-lease","analyzedSha":"dad5a33865fc81a2e55b3b60746632f615ec1e3a","analyzedAt":"2026-08-30T13:49:18.474Z","contentChangedAt":"2026-08-30T13:49:18.474Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}