tinyhumansai/openhuman · error
unsupported delay unit '{unit}', use s/m/h/d
Error message
unsupported delay unit '{unit}', use s/m/h/d What it means
parse_human_delay accepts exactly the units s, m, h and d (seconds/minutes/hours/days), defaulting to minutes when no suffix is given. Any other suffix — ms, w, min, sec — bails with this message. Decimals also fail: the split takes the leading digit run, so '1.5h' leaves unit '.5h'.
Source
Thrown at src/openhuman/cron/ops.rs:147
/// Parse a human-friendly delay string (e.g. "5m", "2h", "30s") into a
/// `chrono::Duration`. Defaults to minutes when no unit is given.
pub fn parse_human_delay(input: &str) -> Result<chrono::Duration> {
let input = input.trim();
if input.is_empty() {
anyhow::bail!("delay must not be empty");
}
let split = input
.find(|c: char| !c.is_ascii_digit())
.unwrap_or(input.len());
let (num, unit) = input.split_at(split);
let amount: i64 = num.parse()?;
let unit = if unit.is_empty() { "m" } else { unit };
let duration = match unit {
"s" => chrono::Duration::seconds(amount),
"m" => chrono::Duration::minutes(amount),
"h" => chrono::Duration::hours(amount),
"d" => chrono::Duration::days(amount),
_ => anyhow::bail!("unsupported delay unit '{unit}', use s/m/h/d"),
};
Ok(duration)
}
pub async fn cron_list(config: &Config) -> Result<RpcOutcome<Vec<CronJob>>, String> {
if !config.cron.enabled {
return Err("cron is disabled by config (cron.enabled=false)".to_string());
}
let jobs = cron::list_jobs(config).map_err(|e| e.to_string())?;
Ok(RpcOutcome::single_log(jobs, "cron jobs listed"))
}
pub async fn cron_update(
config: &Config,
job_id: &str,
patch: CronJobPatch,
) -> Result<RpcOutcome<CronJob>, String> {
if job_id.trim().is_empty() {View on GitHub (pinned to 7491200858)
Solutions
- Rewrite the value with a supported unit: 500ms → 1s, 2w → 14d, 10min → 10m
- Compound values are not supported: 1h30m → 90m
- A bare number means minutes — append s/h/d explicitly when you mean anything else
Example fix
# before --delay 500ms # after --delay 1s
Defensive patterns
Strategy: validation
Validate before calling
fn valid_delay(s: &str) -> bool {
let t = s.trim();
let split = t.find(|c: char| !c.is_ascii_digit()).unwrap_or(t.len());
let (num, unit) = t.split_at(split);
!num.is_empty()
&& matches!(if unit.is_empty() { "m" } else { unit }, "s" | "m" | "h" | "d")
} Type guard
const DELAY_RE = /^(\d+)(s|m|h|d)?$/;
function isValidDelay(input: string): boolean {
return DELAY_RE.test(input.trim());
} Prevention
- Offer a units dropdown (s/m/h/d) in UIs instead of free text
- Rescale millisecond values to whole seconds before sending
- Remember: no compound or decimal durations — pre-compute a single integer plus unit
When it happens
Trigger: Passing 500ms (milliseconds are unsupported — whole-second granularity), 2w, 10min, 1.5h, 90sec, or wrong-case suffixes like 5M; any free-text delay field that assumes Go/ISO-8601 duration syntax.
Common situations: Assuming PT30M / 30min / 1h30m style durations are accepted; converting timeouts from millisecond-based tools without rescaling; UI free-text inputs for delays.
Related errors
- delay must not be empty
- Invalid cron expression: {expression} (expected 5, 6, or 7 f
- Failed to parse service CLI output as JSON: ${err instanceof
- Not running in Tauri
- At least one of --expression, --tz, --command, or --name mus
AI-assisted analysis of tinyhumansai/openhuman@7491200858 (2026-08-17).
Data as JSON: /api/errors/fd7453d95a04dc6b.
Report an issue: GitHub.