{"record":{"id":"7eceae3d3636c47d","repo":"block/buzz","slug":"deletion-request-is-not-runnable-is-blocked-or-i","errorCode":null,"errorMessage":"deletion request is not runnable, is blocked, or is leased by another executor","messagePattern":"deletion request is not runnable, is blocked, or is leased by another executor","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/buzz-deletion/src/lib.rs","lineNumber":824,"sourceCode":"            return Ok(0);\n        }\n        let claim = match request_id {\n            Some(id) => {\n                services\n                    .store\n                    .claim_specific(id, &executor_id, DEFAULT_LEASE_DURATION)\n                    .await?\n            }\n            None => {\n                services\n                    .store\n                    .claim_next(&executor_id, DEFAULT_LEASE_DURATION)\n                    .await?\n            }\n        };\n        let Some(claim) = claim else {\n            if mode == LoopMode::Run && !ran {\n                anyhow::bail!(\n                    \"deletion request is not runnable, is blocked, or is leased by another executor\"\n                );\n            }\n            return Ok(0);\n        };\n        ran = true;\n        let output = execute_claim(&services, mode, claim, &shutdown).await?;\n        print_json(&output)?;\n        let failed = output.last_error.is_some() || output.blocked_reason.is_some();\n        if mode == LoopMode::Run || shutdown.is_cancelled() || failed {\n            return Ok(i32::from(failed));\n        }\n    }\n}\n\nasync fn stop_claim_executor(\n    services: &Services,\n    mode: LoopMode,","sourceCodeStart":806,"sourceCodeEnd":842,"githubUrl":"https://github.com/block/buzz/blob/f956e6fe06a76e50cbd8fba1a162482e752e7f1a/crates/buzz-deletion/src/lib.rs#L806-L842","documentation":"In LoopMode::Run (the single-shot 'run' invocation), the executor asked the store for a claim — claim_specific(id) when --id was passed, otherwise claim_next(executor_id) — and got None back. None means the store found no claimable request: the target request is not in a runnable stage, is blocked (blocked_reason set), or its lease is held by another executor and not yet expired. Because 'run' implies the operator expected work to happen, the absence of any claim (and nothing having run yet, !ran) is surfaced as an error instead of a silent zero exit. In loop mode the same condition just returns 0 — a quiet poll.","triggerScenarios":"`buzz-deletion run --id <uuid>` when that request is still awaiting approval (Submitted/Inventoried), blocked by a dependency, or another executor/loop holds its lease; bare `buzz-deletion run` when every queued request is blocked or leased elsewhere (e.g. the loop daemon is already running against the same DB).","commonSituations":"Operator submits then immediately runs without the approval step; running the one-shot CLI while the long-lived loop executor is mid-deletion; retrying run for a request that previously failed into a blocked state; lease not yet expired after a crashed executor (DEFAULT_LEASE_DURATION must elapse before reclaim).","solutions":["Check the request's state first (store listing/admin output): if it is Submitted or Inventoried, advance it through the explicit approval boundary before running.","If a blocked_reason is recorded, resolve that blocker (or abort) — blocked requests are never claimable.","If another executor (loop daemon) is live, let it own the request or stop it, then wait out the lease duration before re-running so the expired lease can be reclaimed.","Pass --id only for a request you have confirmed is approved and unleased; a bare run is the right form for 'pick up whatever is ready'."],"exampleFix":"# before: run issued before approval\nbuzz-deletion submit --host localhost:3000 --requester npub1... --reason gdpr\nbuzz-deletion run --id <request-id>\n# error: deletion request is not runnable, is blocked, or is leased by another executor\n\n# after: approve first, then run\nbuzz-deletion approve --id <request-id>\nbuzz-deletion run --id <request-id>","handlingStrategy":"retry","validationCode":"# preflight: confirm the request is approved and unleased before one-shot run\npsql \"$DATABASE_URL\" -c \"SELECT id, stage, blocked_reason, lease_expires_at FROM deletion_requests WHERE id = '<uuid>';\"\n# runnable only if stage is approved-or-later, blocked_reason IS NULL, and no live lease","typeGuard":null,"tryCatchPattern":"# safe to retry after backoff >= lease duration: claim is atomic and idempotent\nrc=1\nfor i in 1 2 3; do buzz-deletion run --id \"$RID\" && { rc=0; break; }; sleep 60; done; exit $rc","preventionTips":["Automate submit → approve → run as distinct gated steps; never chain submit directly into run.","Run exactly one executor (loop daemon OR one-shot CLI) per database to avoid lease races.","After a crashed executor, wait out DEFAULT_LEASE_DURATION before re-running so the lease can be reclaimed."],"tags":["buzz-deletion","lease","work-queue","state-machine","executor"],"backgroundTag":"lease-contention","analyzedSha":"f956e6fe06a76e50cbd8fba1a162482e752e7f1a","analyzedAt":"2026-08-16T22:11:40.750Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}