{"record":{"id":"2ee6b5e953b50c42","repo":"BerriAI/litellm","slug":"unsupported-duration-unit-passed-duration-durat","errorCode":null,"errorMessage":"Unsupported duration unit, passed duration: {duration}","messagePattern":"Unsupported duration unit, passed duration: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/duration_parser.py","lineNumber":106,"sourceCode":"\n        target_day = min(target_day, last_day_of_target_month)\n\n        next_month: Final = datetime(\n            year=target_year,\n            month=target_month,\n            day=target_day,\n            hour=current_time.hour,\n            minute=current_time.minute,\n            second=current_time.second,\n            microsecond=current_time.microsecond,\n        )\n\n        # Calculate the duration until the first day of the next month\n        duration_until_next_month: Final = next_month - current_time\n        return int(duration_until_next_month.total_seconds())\n\n    else:\n        raise ValueError(f\"Unsupported duration unit, passed duration: {duration}\")\n\n\ndef get_next_standardized_reset_time(\n    duration: str,\n    current_time: datetime,\n    timezone_str: str = \"UTC\",\n    reset_time_of_day: time = time(0, 0),\n) -> datetime:\n    \"\"\"\n    Get the next standardized reset time based on the duration.\n\n    All durations will reset at predictable intervals, aligned from the current time:\n    - Nd: If N=1, reset at the next `reset_time_of_day`; if N>1, reset every N days from now\n    - Nh: Every N hours, aligned to hour boundaries (e.g., 1:00, 2:00)\n    - Nm: Every N minutes, aligned to minute boundaries (e.g., 1:05, 1:10)\n    - Ns: Every N seconds, aligned to second boundaries\n\n    Parameters:","sourceCodeStart":88,"sourceCodeEnd":124,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/duration_parser.py#L88-L124","documentation":"The terminal else of the duration-to-seconds logic: the value/unit pair was extracted, but the unit is not one of the supported set ('', 's', 'm', 'h', 'd', 'w', 'mo'), so the code cannot compute a duration and raises ValueError including the original string. Note the leading-digits regex is not end-anchored, so trailing junk usually surfaces here rather than at error 571.","triggerScenarios":"Durations like '1y' (year — unsupported), '1x', '30sec' or '1d12h' (the match grabs '1d' or unit-less digits but subsequent parsing of leftovers fails / unit unknown), '0.5d'. Basically any integer+letter combination whose unit is not in {s,m,h,d,w,mo} or any string with text after a valid prefix that the downstream switch cannot handle.","commonSituations":"Users naturally writing '1y' for annual budgets or '1hr'; copy-pasted ISO-8601 ('P1D') or cron-ish values; config generated by templating that appends units litellm does not know.","solutions":["Convert to supported units: '1y' -> '365d' (or '12mo' only where 1-month resets apply), '1hr' -> '1h', '30sec' -> '30s'.","Compound durations must be split and summed as separate supported values, or precomputed to plain seconds ('25h' -> '90000').","Add a unit whitelist check in your config pipeline so unsupported units fail at deploy time with a clear message."],"exampleFix":"# before\nbudget_duration=\"1y\"     # 'y' is not a supported unit\n\n# after\nbudget_duration=\"365d\"   # express years in days\n# or seconds directly: \"31536000\"","handlingStrategy":"validation","validationCode":"import re\n\nSUPPORTED_UNITS = {\"\", \"s\", \"m\", \"h\", \"d\", \"w\", \"mo\"}\n\ndef is_supported_duration(v: str) -> bool:\n    m = re.match(r\"^(\\d+)(mo|[smhdw]?)$\", v.strip())\n    return bool(m) and m.group(2) in SUPPORTED_UNITS\n\nassert not is_supported_duration(\"1y\")\nassert is_supported_duration(\"365d\")","typeGuard":"def has_supported_unit(v: object) -> bool:\n    if not isinstance(v, str):\n        return False\n    m = re.match(r\"^(\\d+)(mo|[smhdw]?)$\", v.strip())\n    return bool(m) and m.group(2) in {\"\", \"s\", \"m\", \"h\", \"d\", \"w\", \"mo\"}","tryCatchPattern":"from litellm.litellm_core_utils.duration_parser import get_duration\ntry:\n    seconds = get_duration(duration)\nexcept ValueError as e:\n    if \"Unsupported duration unit\" in str(e):\n        duration = convert_to_supported(duration)  # '1y'->'365d', '1hr'->'1h'\n        seconds = get_duration(duration)\n    else:\n        raise","preventionTips":["Expose only whitelisted units in config schemas/UI.","Pre-translate human units (y, hr, sec) at your boundary.","Compound durations: sum precomputed seconds instead of passing raw strings."],"tags":["duration-parser","budget","units","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}