block/buzz · error · anyhow::Error
deletion request is not runnable, is blocked, or is leased…
Error message
deletion request is not runnable, is blocked, or is leased by another executor
What it means
The executor tried to lease a deletion request and got nothing: with an explicit id, claim_specific failed because the request does not exist, is not in a claimable state, is blocked, or holds a live lease from another executor (DEFAULT_LEASE_DURATION); without an id, claim_next found zero runnable requests. LoopMode::Run (run-to-completion) treats this as a hard failure instead of idling.
Solutions
- Inspect the request's stage, blocked_reason, and lease columns via the store/CLI (list/show) to see which of the three conditions applies
- If leased: wait for DEFAULT_LEASE_DURATION to expire or stop the other executor, then retry
- If pending approval or blocked: complete the approval/unblock step for that request first
- Retry without --id to let claim_next pick up whatever is runnable
Example fix
# before buzz-deletion run --id <request-id> # fails: leased/blocked # after buzz-deletion show <request-id> # check stage + lease owner # then wait for lease expiry or stop the other executor, and re-run
Defensive patterns
Strategy: retry
Validate before calling
-- Pre-flight in an ops script: only run when a claimable request exists SELECT id, stage, blocked_reason, lease_expires_at, leased_by FROM deletion_requests WHERE id = :id AND blocked_reason IS NULL AND (lease_expires_at IS NULL OR lease_expires_at < now());
Try / catch
// Wrap executor invocations; distinguish 'nothing claimable' from real failures
match run_executor(id).await {
Err(e) if e.to_string().contains("not runnable") => {
// transient: lease held or waiting on approval — back off and retry later
tokio::time::sleep(Duration::from_secs(30)).await;
}
Err(e) => return Err(e),
Ok(n) => { /* ... */ }
} Prevention
- Run exactly one deletion executor per database unless leases are short relative to your retry cadence
- Make orchestration scripts stage-aware: check stage/blocked_reason/lease columns before invoking run
- Treat a lease as authoritative — never bypass claim_next/claim_specific with direct state writes
When it happens
Trigger: Running the executor in Run mode with --id for a request that is still pending approval, blocked on a dependency, or leased by a concurrent executor whose lease has not expired; or running with no eligible work at all.
Common situations: Two executors pointed at the same database (staging leftover process still holds the lease); re-running right after a crashed executor before lease expiry; forgetting that the request needs explicit member approval first.
Related errors
- another storage-snapshot worker already holds the lease
- cannot derive community host from RELAY_URL; pass --host or…
- classify mutation result
- --host must not be empty
- repo announcement rejected by community deletion fence
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-20).
Data as JSON: /api/errors/7eceae3d3636c47d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/buzz-deletion/src/lib.rs:978
return Ok(0);
}
let claim = match request_id {
Some(id) => {
services
.store
.claim_specific(id, &executor_id, DEFAULT_LEASE_DURATION)
.await?
}
None => {
services
.store
.claim_next(&executor_id, DEFAULT_LEASE_DURATION)
.await?
}
};
let Some(claim) = claim else {
if mode == LoopMode::Run && !ran {
anyhow::bail!(
"deletion request is not runnable, is blocked, or is leased by another executor"
);
}
return Ok(0);
};
ran = true;
let output = execute_claim(&services, mode, claim, &shutdown).await?;
print_json(&output)?;
let failed = output.last_error.is_some() || output.blocked_reason.is_some();
if mode == LoopMode::Run || shutdown.is_cancelled() || failed {
return Ok(i32::from(failed));
}
}
}
async fn stop_claim_executor(
services: &Services,
mode: LoopMode,View on GitHub (pinned to dad5a33865)