block/buzz · error

repo announcement lost community serving lease: {error}

Error message

repo announcement lost community serving lease: {error}

What it means

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.

Source

Thrown at crates/buzz-relay/src/handlers/side_effects.rs:2686

    // and pointer below are external S3 effects, so acquire the durable
    // serving-write lease immediately before that sequence. Once acquired,
    // deletion must drain this lease before it can freeze the final object list.
    let serving_write = buzz_deletion::acquire_serving_write(
        &state.db,
        tenant.community(),
        "git_repo_announcement",
    )
    .await
    .map_err(|e| anyhow::anyhow!("repo announcement rejected by community deletion fence: {e}"))?;

    #[cfg(test)]
    if let Some(gate) = &hooks.post_lease_gate {
        gate.reached.notify_one();
        gate.resume.notified().await;
    }

    if let Err(error) = serving_write.verify().await {
        return Err(anyhow::anyhow!(
            "repo announcement lost community serving lease: {error}"
        ));
    }

    // Establish/confirm the manifest pointer, keeping the invariant
    // "repo announced ⟺ pointer exists" so the read path can rely on
    // pointer-absent meaning never-announced (keeping `info_refs`'s fail-closed
    // `Ok(None) → 404` unambiguous). Two distinct cases:
    //
    // - Fresh `Reserved` claim → `seed_manifest_pointer` (strict). This creates
    //   the empty pointer, and correctly *fails* if a non-empty pointer already
    //   exists for a name we just reserved — that would be a suspicious stale
    //   pointer from a prior repo lifecycle, not a legitimate re-announce.
    // - Same-owner `AlreadyOwned` (re-announce) → `ensure_manifest_pointer`
    //   (tolerant). A non-empty pointer is the *normal* post-push state, so
    //   re-announce must accept it untouched; only an absent pointer is
    //   repaired by seeding. Using the strict seed here would wrongly reject
    //   every re-announce after the first push.

View on GitHub (pinned to dad5a33865)

Solutions

  1. Retry the whole announcement from scratch — a fresh acquire_serving_write will now correctly fail-fast or succeed if deletion finished.
  2. Confirm whether the community was deleted; if so, stop publishing announcements to it.
  3. Reduce work performed between lease acquisition and verify by keeping the handler's pre-write steps short.
  4. Check wrapped {error} from verify() to confirm the fence-close cause and timing.
Defensive patterns

Strategy: retry

Validate before calling

// re-check the lease immediately before each write
serving_write.verify().await.map_err(|e| anyhow!("lease lost pre-write: {e}"))?;

Try / catch

if let Err(error) = serving_write.verify().await {
    tracing::warn!("announcement lost lease, retrying: {error}");
    return retry_announcement(event, 1).await; // full re-acquire path
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30). Data as JSON: /api/errors/47120656a3e76478. Report an issue: GitHub.