block/buzz · critical · anyhow::Error

Community deletion serving fence is unsafe: {e}

Error message

Community deletion serving fence is unsafe: {e}

What it means

Fatal startup error from db.validate_deletion_serving_catalog(), which verifies the catalog backing the community-deletion serving fence — the mechanism that keeps a half-deleted community from serving stale events. If catalog shape or contents cannot be proven safe, the relay refuses to boot rather than serve potentially unfenced data. The source notes migration 0021 as the floor-guard schema this depends on.

Source

Thrown at crates/buzz-relay/src/main.rs:206

    let auto_migrate =
        buzz_auto_migrate_enabled(std::env::var("BUZZ_AUTO_MIGRATE").ok().as_deref());
    if auto_migrate {
        db.migrate().await.map_err(|e| {
            error!("Failed to run database migrations: {e}");
            anyhow::anyhow!("Database migration failed: {e}")
        })?;
        info!("Database migrations complete");
    } else {
        info!("Skipping database migrations because BUZZ_AUTO_MIGRATE is not enabled");
    }

    if let Err(e) = db.ensure_future_partitions(3).await {
        error!("Failed to ensure partitions: {e}");
    }

    db.validate_deletion_serving_catalog().await.map_err(|e| {
        error!("Community deletion serving-fence validation failed: {e}");
        anyhow::anyhow!("Community deletion serving fence is unsafe: {e}")
    })?;
    info!("Community deletion serving fences verified");

    // Freshness fence probe: cursor pages route to the replica only for
    // history the probe has verified as fully replayed. Deliberately AFTER
    // the migration decision: spawn_fence_probe first verifies the
    // commit-time floor guard (catalog shape + observed behavior through the
    // armed pool) against the live schema, so a relay running with
    // BUZZ_AUTO_MIGRATE off and migration 0021 unapplied can never open the
    // fence over an unenforced floor. Verification failure is loud but
    // non-fatal: the fence stays closed and every cursor page routes to the
    // writer.
    match db.spawn_fence_probe().await {
        Ok(true) => info!("Replica fence probe started (floor guard verified)"),
        Ok(false) => {}
        Err(e) => {
            error!(
                "Replica fence disabled — floor guard verification failed: {e}. \

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Apply pending migrations (enable BUZZ_AUTO_MIGRATE once, or run them manually), then restart
  2. Inspect {e} for the specific catalog/table mismatch it names
  3. Compare the live schema against migrations/ up to HEAD, focusing on the deletion-serving fence migration
  4. If the catalog was hand-edited, restore from a known-good backup rather than patching rows
Defensive patterns

Strategy: validation

Validate before calling

# Fence depends on current schema: assert applied migrations match migrations/ HEAD.
latest=$(ls migrations | grep -oE '^[0-9]+' | sort -n | tail -1)
applied=$(psql "$DATABASE_URL" -tAc "select max(version) from _sqlx_migrations")
[ "$latest" = "$(echo $applied | tr -d ' ')" ] || { echo 'fence catalog may be stale: apply migrations'; exit 1; }

Prevention

When it happens

Trigger: Running with BUZZ_AUTO_MIGRATE off while fence-related migrations (0021 era) are unapplied; fence catalog tables missing or malformed; manually edited catalog rows.

Common situations: New binary against a database whose migrations are pinned/managed externally and one was skipped; partial database restore; environments where DBAs cherry-pick migrations.

Related errors


AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16). Data as JSON: /api/errors/a937a169e15458e6. Report an issue: GitHub.