block/buzz · error
gate off
Error message
gate off
What it means
This is `.expect("gate off")` on `db.is_relay_member(cid, &writer_only)` in `is_relay_member_is_bounded_routed_and_fails_closed`. With the replica-read budget unset, the membership check must be answered from the writer; the expect panics if the query returns Err rather than a boolean. Note the expect unwraps a `Result<bool, _>`, so Err propagates as a panic with the message "gate off".
Source
Thrown at crates/buzz-db/src/runtime/tests.rs:1698
}
let cid = CommunityId::from_uuid(community);
let writer_only = "aa".repeat(32);
let replica_only = "bb".repeat(32);
relay_members::add_relay_member(&writer, cid, &writer_only, "member", None)
.await
.expect("seed writer member");
relay_members::add_relay_member(&replica, cid, &replica_only, "member", None)
.await
.expect("seed replica member");
let mut db = Db::from_pools(writer.clone(), replica.clone());
db.fence().force_open_for_tests(chrono::Utc::now());
// Budget unset ⇒ bounded arm disabled ⇒ writer.
assert!(
db.is_relay_member(cid, &writer_only)
.await
.expect("gate off"),
"budget unset must answer from the writer"
);
assert!(!db.is_relay_member(cid, &replica_only).await.unwrap());
// Budget set + fresh entry ⇒ replica.
db.set_replica_read_max_age_for_tests(Some(std::time::Duration::from_secs(5)));
assert!(
db.is_relay_member(cid, &replica_only)
.await
.expect("gate on"),
"budget set must answer from the replica"
);
assert!(!db.is_relay_member(cid, &writer_only).await.unwrap());
// Entry older than the budget ⇒ fail closed to the writer. Close
// first so no prior fresh entry can be the one proved (matches the
// count test; today `force_open_for_tests_at` also clears the ring).
db.fence().close();View on GitHub (pinned to dad5a33865)
Solutions
- Ensure Postgres is running and both scratch DBs are created and migrated before the query.
- Verify the seed steps (`insert community`, both `add_relay_member` calls) succeeded on the writer.
- Print the inner error: `.unwrap_or_else(|e| panic!("is_relay_member (gate off) failed: {e}"))`.
- Confirm `Db::from_pools(writer, replica)` got live pools, not ones already dropped by `drop_scratch_db`.
- Check `relay_members` membership query still compiles against the current schema.
Example fix
// before
db.is_relay_member(cid, &writer_only).await.expect("gate off")
// after
db.is_relay_member(cid, &writer_only).await
.unwrap_or_else(|e| panic!("is_relay_member (gate off / writer) failed: {e}")) Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check: writer reachable and member seeded before the routed check
let seeded: i64 = sqlx::query_scalar("SELECT COUNT(*) FROM relay_members WHERE pubkey=$1")
.bind(&writer_only).fetch_one(&writer).await.unwrap_or(0);
assert_eq!(seeded, 1, "writer-only member must be seeded first"); Type guard
fn membership_result_ok(r: &Result<bool, sqlx::Error>) -> bool { r.is_ok() } Try / catch
match db.is_relay_member(cid, &writer_only).await {
Ok(found) => assert!(found),
Err(e) => panic!("is_relay_member failed (gate off): {e}"),
} Prevention
- Run seeding asserts before routed membership checks
- Keep both pools open for the whole test lifetime
- With the budget unset, expect the writer to answer — an Err indicates infra, not routing
- Print inner sqlx errors for diagnosability instead of bare expect labels
When it happens
Trigger: Calling `is_relay_member` on the writer-routed arm when the writer pool is unreachable, the `relay_members`/`communities` tables are missing in the scratch DB, or the community id has no row (FK/JOIN error in the membership query).
Common situations: Seeding steps above failed silently (but their expects would have panicked first); running the ignored test without Postgres; schema drift in `relay_members` after a migration change; pool closed between fence setup and the query.
Related errors
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30).
Data as JSON: /api/errors/047b0c90b3c99508.
Report an issue: GitHub.