block/buzz · error

timeout failed: {e}

Error message

timeout failed: {e}

What it means

The 'timeout' arm of `run_atomic_mutation` wraps any failure from `state.db.execute_timeout_with_marker` with 'timeout failed: {e}'. The context was complete (target and expiry present), but the database-side timeout operation failed, and the error is re-wrapped for the enforcement driver's bookkeeping.

Source

Thrown at crates/buzz-relay/src/handlers/report_resolution.rs:720

            let target = ctx
                .target_pubkey
                .ok_or_else(|| anyhow::anyhow!("timeout requires target_pubkey"))?;
            let until = ctx
                .timeout_until
                .ok_or_else(|| anyhow::anyhow!("timeout requires timeout_until"))?;
            state
                .db
                .execute_timeout_with_marker(
                    action_id,
                    lease_token,
                    ctx.community_id,
                    target,
                    ctx.actor_pubkey,
                    until,
                    ctx.reason,
                )
                .await
                .map_err(|e| anyhow::anyhow!("timeout failed: {e}"))
        }
        "kick" => {
            let target = ctx
                .target_pubkey
                .ok_or_else(|| anyhow::anyhow!("kick requires target_pubkey"))?;
            let ch = ctx
                .channel_id
                .ok_or_else(|| anyhow::anyhow!("kick requires channel_id"))?;
            match state
                .db
                .execute_kick_with_marker(
                    action_id,
                    lease_token,
                    ctx.community_id,
                    ch,
                    target,
                    ctx.actor_pubkey,
                )

View on GitHub (pinned to eed74bde2f)

Solutions

  1. Inspect the inner `{e}` message in the error chain for the concrete DB cause.
  2. Treat lease/marker conflicts as 'already applied' — the atomic marker makes timeouts idempotent per action_id.
  3. Check Postgres availability and schema migrations; run `just test` integration suite to reproduce locally.
  4. Retry the driver on transient errors; skip actions whose marker shows another driver completed them.

Example fix

// before
execute_timeout_with_marker(...).await.map_err(|e| anyhow!("timeout failed: {e}"))
// after — tolerate already-applied marker
match execute_timeout_with_marker(...).await {
  Ok(applied) => Ok(applied),
  Err(e) if e.to_string().contains("marker already set") => Ok(false),
  Err(e) => Err(anyhow!("timeout failed: {e}")),
}
Defensive patterns

Strategy: retry

Validate before calling

anyhow::ensure!(ctx.target_pubkey.is_some(), "timeout needs target");
anyhow::ensure!(ctx.timeout_until.is_some(), "timeout needs expiry");
anyhow::ensure!(ctx.timeout_until.unwrap() > chrono::Utc::now(), "expiry must be future");

Try / catch

for attempt in 0..3 {
  match run_atomic_mutation(&state, ctx).await {
    Ok(applied) => break Ok(applied),
    Err(e) if e.to_string().contains("timeout failed") && attempt < 2 && is_transient(&e) => {
      tokio::time::sleep(backoff(attempt)).await; // idempotent via action marker
    }
    Err(e) => break Err(e),
  }
}

Prevention

When it happens

Trigger: Calling `execute_timeout_with_marker` when the DB operation errors: lease/marker conflict from a concurrent driver, missing user/community rows, invalid timestamp comparison, constraint violation, or Postgres connectivity failure.

Common situations: Two drivers racing to apply the same timeout action; the timed-out user record removed before enforcement; clock/timestamp values out of range for the DB column; transient Postgres outages under load.

Understand the failure class

Related errors


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