{"record":{"id":"cb4edff32b4c1597","repo":"tinyhumansai/openhuman","slug":"cron-job-job-id-not-found","errorCode":null,"errorMessage":"Cron job '{job_id}' not found","messagePattern":"Cron job '(.+?)' not found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/cron/store.rs","lineNumber":268,"sourceCode":"        }\n        Ok(jobs)\n    })\n}\n\npub fn get_job(config: &Config, job_id: &str) -> Result<CronJob> {\n    with_connection(config, |conn| {\n        let mut stmt = conn.prepare(\n            \"SELECT id, expression, command, schedule, job_type, prompt, name, session_target, model,\n                    enabled, delivery, delete_after_run, created_at, next_run, last_run, last_status, last_output,\n                    agent_id, profile_id\n             FROM cron_jobs WHERE id = ?1\",\n        )?;\n\n        let mut rows = stmt.query(params![job_id])?;\n        if let Some(row) = rows.next()? {\n            map_cron_job_row(row).map_err(Into::into)\n        } else {\n            anyhow::bail!(\"Cron job '{job_id}' not found\")\n        }\n    })\n}\n\npub fn remove_job(config: &Config, id: &str) -> Result<()> {\n    let changed = with_connection(config, |conn| {\n        conn.execute(\"DELETE FROM cron_jobs WHERE id = ?1\", params![id])\n            .context(\"Failed to delete cron job\")\n    })?;\n\n    if changed == 0 {\n        anyhow::bail!(\"Cron job '{id}' not found\");\n    }\n\n    println!(\"✅ Removed cron job {id}\");\n    Ok(())\n}\n","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/749120085864ce16e0f273c7b86fac7740b39c5b/src/openhuman/cron/store.rs#L250-L286","documentation":"get_job ran SELECT ... FROM cron_jobs WHERE id = ?1 and got no row back, so the lookup bails naming the missing id. Every id-addressed cron operation (get, update, run) funnels through this read and reports not-found identically.","triggerScenarios":"cron.get/update/run-now with an id from a stale listing (job deleted meanwhile); a typo'd or case-mismatched id; operating against a different workspace — config.workspace_dir is per-user/per-workspace, so the cron.db being queried is not the one holding the job.","commonSituations":"Two terminals with different OPENHUMAN_WORKSPACE/action_dir; a job removed from another UI session or by another admin; ids copied from truncated 'cron list' output; scripts referencing ids after a workspace migration.","solutions":["Run cron list (cron_list) and re-copy the exact id","Verify the workspace: check config.workspace_dir / OPENHUMAN_WORKSPACE and the active user profile","If the job is gone, re-create it and update the referencing script with the new id"],"exampleFix":"# before\nopenhuman cron update 6f1c2a... --name x   # stale id\n\n# after\nopenhuman cron list                        # find the current id\nopenhuman cron update <fresh-id> --name x","handlingStrategy":"try-catch","validationCode":"let exists = list_jobs(&config)?.iter().any(|j| j.id == id);\nif !exists {\n    // skip / prompt instead of erroring downstream\n}","typeGuard":null,"tryCatchPattern":"let job = get_job(&config, id).map_err(|e| {\n    if e.to_string().contains(\"not found\") { ApiError::NotFound(id.to_string()) } else { ApiError::Internal(e) }\n})?; // surface 404-style to the caller and offer a list refresh","preventionTips":["Refresh the job list before id-addressed operations in long-lived UIs","Scope scripts to one workspace explicitly rather than relying on ambient env","Treat not-found as an expected branch, not an exception path, in job editors"],"tags":["cron","store","not-found","id"],"backgroundTag":"record-not-found","analyzedSha":"749120085864ce16e0f273c7b86fac7740b39c5b","analyzedAt":"2026-08-17T21:21:45.363Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}