{"record":{"id":"93a68affd0e0767b","repo":"langchain-ai/deepagents","slug":"schedule-duration-must-use-m-for-minutes-or-h","errorCode":null,"errorMessage":"schedule duration must use 'm' for minutes or 'h' for hours","messagePattern":"schedule duration must use 'm' for minutes or 'h' for hours","errorType":"validation","errorClass":"CronJobError","httpStatus":null,"severity":"error","filePath":"libs/talon/deepagents_talon/cron/jobs.py","lineNumber":687,"sourceCode":"    next_run_at = cast(\"datetime\", job.next_run_at)\n    interval = timedelta(minutes=job.schedule.minutes)\n    while next_run_at <= now:\n        next_run_at += interval\n    return replace(job, repeat=repeat, next_run_at=next_run_at)\n\n\ndef _parse_duration_minutes(value: str) -> int:\n    parts = value.split()\n    if len(parts) != 1:\n        msg = \"schedule duration must be a single value such as '30m'\"\n        raise CronJobError(msg)\n    text = parts[0]\n    if text.endswith(\"m\"):\n        return _positive_int(text[:-1])\n    if text.endswith(\"h\"):\n        return _positive_int(text[:-1]) * 60\n    msg = \"schedule duration must use 'm' for minutes or 'h' for hours\"\n    raise CronJobError(msg)\n\n\ndef _positive_int(value: str) -> int:\n    if not value.isdecimal():\n        msg = \"schedule duration must be a positive integer\"\n        raise CronJobError(msg)\n    number = int(value)\n    if number < MIN_GRANULARITY_MINUTES:\n        msg = \"schedule duration must be at least 1 minute\"\n        raise CronJobError(msg)\n    return number\n\n\ndef _same_origin_scope(left: CronOrigin, right: CronOrigin) -> bool:\n    return left.conversation_id == right.conversation_id and left.channel == right.channel\n\n\ndef _coerce_utc(value: datetime | None = None) -> datetime:","sourceCodeStart":669,"sourceCodeEnd":705,"githubUrl":"https://github.com/langchain-ai/deepagents/blob/a1af029e6e73cb17c36bff823d227747b28e91e1/libs/talon/deepagents_talon/cron/jobs.py#L669-L705","documentation":"CronJobError raised by `_parse_duration_minutes` in libs/talon/deepagents_talon/cron/jobs.py when parsing a schedule duration string that does not end in 'm' (minutes) or 'h' (hours). The library only accepts these two unit suffixes so schedule granularity stays unambiguous and minute-based. Any other suffix (e.g. 's', 'd', 'w') or no suffix at all is rejected.","triggerScenarios":"Calling `parse` (via the cron job creation API) with a schedule duration like '30s', '2d', '45', or '1m30s'. The suffix check `text.endswith('m')` / `endswith('h')` fails and the error is raised.","commonSituations":"Developers copying cron-style syntax that supports seconds or days; passing a bare number without a unit; writing durations like '90min' or '1hr' with long unit names; migrating configs from other schedulers that accept 'd' or 's'.","solutions":["Append a supported unit suffix: use 'm' for minutes (e.g. '30m') or 'h' for hours (e.g. '2h').","Convert other units yourself before passing: seconds to minutes, days to hours (e.g. '2d' -> '48h').","Ensure the string is a plain duration token with no extra text, spaces, or compound parts (e.g. '1h30m' is not accepted)."],"exampleFix":"// before\nparse(\"90min\", ...)\nparse(\"2d\", ...)\n// after\nparse(\"90m\", ...)\nparse(\"48h\", ...)","handlingStrategy":"validation","validationCode":"import re\n_DURATION_RE = re.compile(r\"^\\d+(m|h)$\")\ndef validate_schedule_duration(text: str) -> bool:\n    return bool(_DURATION_RE.match(text.strip()))","typeGuard":"def is_valid_duration(text: str) -> bool:\n    return isinstance(text, str) and text.endswith((\"m\", \"h\")) and text[:-1].isdecimal()","tryCatchPattern":"from deepagents_talon.cron.jobs import CronJobError\ntry:\n    job = parse(schedule)\nexcept CronJobError as exc:\n    logger.error(\"invalid schedule %r: %s\", schedule, exc)\n    raise ValueError(f\"bad schedule {schedule!r}\") from exc","preventionTips":["Always attach a unit suffix: 'm' for minutes or 'h' for hours.","Convert seconds/days to minutes/hours before calling the API.","Validate the schedule with a regex before passing it to `parse`."],"tags":["cron","validation","scheduling","argument-parsing"],"backgroundTag":"invalid-duration-format","analyzedSha":"a1af029e6e73cb17c36bff823d227747b28e91e1","analyzedAt":"2026-08-29T11:43:24.718Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}