block/buzz · error
count, entry too old
Error message
count, entry too old
What it means
This is `.expect("count, entry too old")` on `count_events_routed` after the fence entry was force-opened with an Instant 10s in the past, making it older than the 5s budget; routing must fail closed to the writer. The expect panics if that writer-served count itself returns Err. It exists to prove the over-budget fallback path still executes a valid query.
Source
Thrown at crates/buzz-db/src/runtime/tests.rs:1649
db.set_replica_read_max_age_for_tests(Some(std::time::Duration::from_secs(5)));
let n = db
.count_events_routed("test_count", &q)
.await
.expect("count, gate on");
assert_eq!(n, 1, "budget set must count on the replica (bounded)");
// Entry older than the budget ⇒ bounded fails ⇒ writer. Covered
// would still hold here (upper <= wall) — proving count never
// consults it.
db.fence().close();
db.fence().force_open_for_tests_at(
chrono::Utc::now(),
std::time::Instant::now() - std::time::Duration::from_secs(10),
);
let n = db
.count_events_routed("test_count", &q)
.await
.expect("count, entry too old");
assert_eq!(
n, 2,
"an over-budget entry must fail the count closed to the writer, \
even when the covered arm would admit the shape"
);
drop_scratch_db(&admin, replica, &rname).await;
drop_scratch_db(&admin, writer, &wname).await;
}
/// Routed relay-membership check: budget unset ⇒ writer; budget set +
/// fresh proved entry ⇒ replica (bounded arm); over-budget entry ⇒
/// writer. Divergent membership rows prove which pool answered.
#[tokio::test]
#[ignore = "requires Postgres"]
async fn is_relay_member_is_bounded_routed_and_fails_closed() {
let admin = PgPool::connect(&admin_url().await)
.awaitView on GitHub (pinned to dad5a33865)
Solutions
- Check the writer pool is still alive after the earlier arms; increase idle timeout or acquire timeout on the pool.
- Verify the routing code fails closed (returns writer result) rather than Err for over-budget fence entries.
- Print the inner sqlx error to distinguish a routing bug from an infra failure.
- Ensure `force_open_for_tests_at` was called with a past Instant as in the test, not the future.
- Re-create scratch DBs fresh; leftover state from prior runs can corrupt seed assumptions.
Example fix
// before
let n = db.count_events_routed("test_count", &q).await.expect("count, entry too old");
// after
let n = db.count_events_routed("test_count", &q).await
.unwrap_or_else(|e| panic!("count (entry too old / fail-closed writer) failed: {e}")); Defensive patterns
Strategy: fallback
Validate before calling
// Ensure fence state matches the intended over-budget scenario
db.fence().close();
db.fence().force_open_for_tests_at(chrono::Utc::now(),
std::time::Instant::now() - std::time::Duration::from_secs(10)); Type guard
fn entry_is_stale(opened_at: std::time::Instant, budget: std::time::Duration) -> bool {
opened_at.elapsed() > budget
} Try / catch
let n = db.count_events_routed("test_count", &q).await
.unwrap_or_else(|e| panic!("fail-closed count failed: {e}")); Prevention
- Remember routing should fail CLOSED (writer), not Err — an Err here is a routing bug
- Keep writer pool alive across all test arms
- Pass a past Instant to force_open_for_tests_at as intended
- Recreate scratch DBs fresh for each run
When it happens
Trigger: Calling `count_events_routed` after `fence().close()` + `force_open_for_tests_at(now, now-10s)` when the writer pool errors (connection lost, schema missing), or when the fence/ring state manipulation itself leaves routing in an error state instead of failing closed.
Common situations: Writer pool idle-timed out during the earlier replica arms of the test; scratch writer DB dropped; a routing-code regression where over-budget entries produce Err instead of falling back to the writer (which is exactly what this test is designed to catch).
Related errors
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30).
Data as JSON: /api/errors/1a62622cdbb16b69.
Report an issue: GitHub.