{"record":{"id":"69e1b69724a948e0","repo":"zeroclaw-labs/zeroclaw","slug":"cron-job-not-found","errorCode":null,"errorMessage":"Cron job '{}' not found","messagePattern":"Cron job '(.+?)' not found","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-runtime/src/cron/store.rs","lineNumber":1599,"sourceCode":"    match action {\n        RunCompletionAction::Reschedule => {\n            let next_run = next_run_for_schedule(&job.schedule, job_state_at)?;\n            let changed = conn\n                .execute(\n                    \"UPDATE cron_jobs\n                     SET next_run = ?1, last_run = ?2, last_status = ?3, last_output = ?4\n                     WHERE id = ?5\",\n                    params![\n                        next_run.to_rfc3339(),\n                        job_state_at.to_rfc3339(),\n                        status,\n                        bounded_output.as_deref(),\n                        job.id,\n                    ],\n                )\n                .context(\"Failed to update cron job run state\")?;\n            if changed == 0 {\n                anyhow::bail!(\"Cron job '{}' not found\", job.id);\n            }\n        }\n        RunCompletionAction::Disable => {\n            let changed = conn\n                .execute(\n                    \"UPDATE cron_jobs\n                     SET enabled = 0, last_run = ?1, last_status = ?2, last_output = ?3\n                     WHERE id = ?4\",\n                    params![\n                        job_state_at.to_rfc3339(),\n                        status,\n                        bounded_output.as_deref(),\n                        job.id,\n                    ],\n                )\n                .context(\"Failed to disable completed one-shot cron job\")?;\n            if changed == 0 {\n                anyhow::bail!(\"Cron job '{}' not found\", job.id);","sourceCodeStart":1581,"sourceCodeEnd":1617,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/cron/store.rs#L1581-L1617","documentation":"apply_run_completion_state runs the post-run UPDATE (last-run timestamp, bounded output) after persist_run_result / persist_run_completion_state record a finished run. SQLite reports 0 rows changed when the cron_jobs row for job.id no longer exists, so the store bails: the job vanished between dispatch and completion, typically deleted by a concurrent connection (CLI delete, gateway API, or sync_declarative_jobs removing a job no longer in config).","triggerScenarios":"A run is in flight while the job row is deleted: running a job removal command from another shell, restarting the daemon after deleting the job from zeroclaw.toml (sync deletes stale declarative jobs), or two scheduler processes sharing one workspace database.","commonSituations":"Cancelling a long-running one-shot job mid-execution; editing zeroclaw.toml and restarting while an overdue declarative job executes; accidentally running duplicate daemons against the same data dir.","solutions":["Check the cron job list (or cron_jobs table): if you deleted the job yourself, the error is benign — the run finished, only its state write had no target row","If the job should still exist, verify it is still declared in zeroclaw.toml (declarative jobs missing from config are deleted on sync) and restart the daemon","Ensure only one scheduler/daemon runs against the workspace database"],"exampleFix":"// before — completion state write aborts the caller\npersist_run_result(&config, &job, &result)?;\n\n// after — tolerate a job deleted mid-run\nif let Err(err) = persist_run_result(&config, &job, &result) {\n    let msg = err.to_string();\n    if msg.starts_with(\"Cron job\") && msg.ends_with(\"not found\") {\n        tracing::warn!(job = %job.id, \"job deleted while run was in flight; dropping completion state\");\n    } else {\n        return Err(err);\n    }\n}","handlingStrategy":"try-catch","validationCode":"// immediately before recording completion state, confirm the row survived\nlet present: i64 = conn\n    .query_row(\n        \"SELECT COUNT(*) FROM cron_jobs WHERE id = ?1\",\n        rusqlite::params![job.id],\n        |r| r.get(0),\n    )\n    .unwrap_or(0);\nif present == 0 {\n    // job was deleted mid-run; skip completion bookkeeping instead of erroring\n}","typeGuard":null,"tryCatchPattern":"if let Err(err) = persist_run_result(&config, &job, &result) {\n    let msg = err.to_string();\n    if msg.starts_with(\"Cron job\") && msg.ends_with(\"not found\") {\n        tracing::warn!(job = %job.id, \"job deleted while run was in flight; dropping completion state\");\n        return Ok(());\n    }\n    return Err(err);\n}","preventionTips":["Run only one daemon/scheduler against a workspace database","When removing declarative jobs from zeroclaw.toml, expect in-flight runs to log this on completion and treat it as expected","Disable a job before deleting it if you need in-flight runs to drain cleanly"],"tags":["cron","sqlite","race-condition"],"backgroundTag":"record-not-found","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}