{"record":{"id":"f9375230a16e8b6a","repo":"NousResearch/hermes-agent","slug":"invalid-duration-s-use-format-like-30m-2","errorCode":null,"errorMessage":"Invalid duration: '{s}'. Use format like '30m', '2h', or '1d'","messagePattern":"Invalid duration: '(.+?)'\\. Use format like '30m', '2h', or '1d'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"cron/jobs.py","lineNumber":603,"sourceCode":"\n\n# =============================================================================\n# Schedule Parsing\n# =============================================================================\n\ndef parse_duration(s: str) -> int:\n    \"\"\"\n    Parse duration string into minutes.\n    \n    Examples:\n        \"30m\" → 30\n        \"2h\" → 120\n        \"1d\" → 1440\n    \"\"\"\n    s = s.strip().lower()\n    match = re.match(r'^(\\d+)\\s*(m|min|mins|minute|minutes|h|hr|hrs|hour|hours|d|day|days)$', s)\n    if not match:\n        raise ValueError(f\"Invalid duration: '{s}'. Use format like '30m', '2h', or '1d'\")\n    \n    value = int(match.group(1))\n    unit = match.group(2)[0]  # First char: m, h, or d\n    \n    multipliers = {'m': 1, 'h': 60, 'd': 1440}\n    return value * multipliers[unit]\n\n\ndef parse_schedule(schedule: str) -> Dict[str, Any]:\n    \"\"\"\n    Parse schedule string into structured format.\n    \n    Returns dict with:\n        - kind: \"once\" | \"interval\" | \"cron\"\n        - For \"once\": \"run_at\" (ISO timestamp)\n        - For \"interval\": \"minutes\" (int)\n        - For \"cron\": \"expr\" (cron expression)\n    ","sourceCodeStart":585,"sourceCodeEnd":621,"githubUrl":"https://github.com/NousResearch/hermes-agent/blob/c896c09c42910c584c4c7d2325b58c14713ea42c/cron/jobs.py#L585-L621","documentation":"ValueError from parse_duration in cron/jobs.py: the string must fully match ^(\\d+)\\s*(m|min|...|h|hr|...|d|day|days)$ after lowercasing/stripping. Anything else — combined units ('1h30m'), '45', '0.5h', 'w' (weeks), or embedded text — fails. Returns minutes via multipliers m=1, h=60, d=1440.","triggerScenarios":"create_job(schedule='1h30m'), schedule='90', schedule='2 hours 15m', or schedule='1w' — all miss the single integer + single unit regex.","commonSituations":"Users typing compound durations; omitting the unit; asking for weeks which the parser doesn't support; passing a raw number from a config file.","solutions":["Use one integer + one unit: '30m', '2h', '1d' (long forms 'mins'/'hours'/'days' also accepted)","Convert weeks to days (7d) and compound durations to the smallest unit ('1h30m' -> '90m')","If a cron-style or timestamp schedule is wanted, pass a 5-field cron expression or ISO timestamp instead of a duration"],"exampleFix":"# before\ncreate_job(schedule=\"1h30m\", ...)\n# ValueError: Invalid duration: '1h30m'. Use format like '30m', '2h', or '1d'\n\n# after\ncreate_job(schedule=\"90m\", ...)","handlingStrategy":"validation","validationCode":"import re\n\n_DURATION_RE = re.compile(r\"^(\\d+)\\s*(m|min|mins|minute|minutes|h|hr|hrs|hour|hours|d|day|days)$\")\n\ndef is_valid_duration(s: str) -> bool:\n    return bool(_DURATION_RE.match(s.strip().lower()))","typeGuard":null,"tryCatchPattern":"from cron.jobs import parse_duration\n\ntry:\n    minutes = parse_duration(raw)\nexcept ValueError:\n    minutes = humanize_to_minutes(raw)  # '1h30m' -> 90, then submit f\"{minutes}m\"","preventionTips":["Submit one integer plus one unit only; convert compound durations to minutes first","Remember weeks are not supported — use '7d'","Validate in the UI with the same single-unit regex"],"tags":["cron","duration","validation","parsing"],"backgroundTag":null,"analyzedSha":"c896c09c42910c584c4c7d2325b58c14713ea42c","analyzedAt":"2026-08-14T17:18:01.089Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}