zeroclaw-labs/zeroclaw · error · anyhow::Error
Declarative cron job '{id}': invalid job_type '{other}', exp
Error message
Declarative cron job '{id}': invalid job_type '{other}', expected 'shell' or 'agent' What it means
validate_decl matches decl.job_type case-insensitively against exactly two accepted values: "shell" and "agent". Any other string (typo, a model name, a provider label) falls into the catch-all arm and the declarative sync aborts before any DB write.
Source
Thrown at crates/zeroclaw-runtime/src/cron/store.rs:1423
"Declarative cron job '{id}': shell job requires a non-empty 'command'"
);
}
}
"agent" => {
if decl.prompt.as_deref().is_none_or(|p| p.trim().is_empty()) {
anyhow::bail!(
"Declarative cron job '{id}': agent job requires a non-empty 'prompt'"
);
}
if decl.shell_output_format != zeroclaw_config::schema::CronShellOutputFormat::default()
{
anyhow::bail!(
"Declarative cron job '{id}': shell_output_format is shell-only and cannot be set on an agent job"
);
}
}
other => {
anyhow::bail!(
"Declarative cron job '{id}': invalid job_type '{other}', expected 'shell' or 'agent'"
);
}
}
Ok(())
}
/// Convert a `CronScheduleDecl` to the runtime `Schedule` type.
fn convert_schedule_decl(decl: &zeroclaw_config::schema::CronScheduleDecl) -> Result<Schedule> {
use zeroclaw_config::schema::CronScheduleDecl;
match decl {
CronScheduleDecl::Cron { expr, tz } => Ok(Schedule::Cron {
expr: expr.clone(),
tz: tz.clone(),
}),
CronScheduleDecl::Every { every_ms } => Ok(Schedule::Every {
every_ms: *every_ms,View on GitHub (pinned to 88bb9c8533)
Solutions
- Set job_type to exactly "shell" or "agent" (any capitalization works because matching is lowercased)
- Double-check for trailing characters or smart quotes when copy-pasting
Example fix
# before
[cron.cleanup]
job_type = "bash"
schedule = { kind = "cron", expression = "0 4 * * *" }
command = "rm -rf /tmp/cache/*"
# after
[cron.cleanup]
job_type = "shell"
schedule = { kind = "cron", expression = "0 4 * * *" }
command = "rm -rf /tmp/cache/*" Defensive patterns
Strategy: type-guard
Validate before calling
for (id, decl) in &decls {
let jt = decl.job_type.to_lowercase();
if jt != "shell" && jt != "agent" {
anyhow::bail!("cron job '{id}': job_type must be 'shell' or 'agent', got '{jt}'");
}
} Type guard
fn is_supported_cron_job_type(job_type: &str) -> bool {
matches!(job_type.to_lowercase().as_str(), "shell" | "agent")
} Try / catch
if let Err(err) = zeroclaw_runtime::cron::sync_declarative_jobs(&config, &decls) {
if err.to_string().contains("invalid job_type") {
eprintln!("config error: job_type must be 'shell' or 'agent' (case-insensitive)");
}
return Err(err);
} Prevention
- Only two job types exist: shell and agent — check against that closed set before writing config
- Beware trailing spaces and smart quotes when pasting job_type values from docs or chats
When it happens
Trigger: job_type = "sh", "bash", "command", "run", "Agent " with trailing garbage, or a model/provider identifier mistakenly placed in the job_type field.
Common situations: Assuming the scheduler accepts arbitrary runner names; pasting a model id into job_type; renaming from another tool's cron config that uses different type names.
Understand the failure class
Background: Config validation failed: what "invalid value for {key}" and settings-rejection errors mean across 19 open-source libraries — this error's family across 19 libraries.
Related errors
- Declarative cron job has empty id
- Declarative cron job '{id}': shell job requires a non-empty
- Declarative cron job '{id}': agent job requires a non-empty
- Declarative cron job '{id}': shell_output_format is shell-on
- ACP request_permission failed: {} ({})
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/12ae93e1f44e396e.
Report an issue: GitHub.