TheAlgorithms/Python · error · ValueError

Invalid unit {invalid_unit} is not in {', '.join(time_chart)

Error message

Invalid unit {invalid_unit} is not in {', '.join(time_chart)}.

What it means

Raised by convert_time() in conversions/time_conversions.py when unit_from or unit_to (after .lower()) is not a key of time_chart: seconds, minutes, hours, days, weeks, months, years, decades, centuries. The invalid one is identified in the message; from-unit is reported if both are bad. Matching is case-insensitive because inputs are lowercased first.

Source

Thrown at conversions/time_conversions.py:71

    >>> convert_time(1, "cool", "century")  # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    ValueError: Invalid unit cool is not in seconds, minutes, hours, days, weeks, ...
    >>> convert_time(1, "seconds", "hot")  # doctest: +ELLIPSIS
    Traceback (most recent call last):
        ...
    ValueError: Invalid unit hot is not in seconds, minutes, hours, days, weeks, ...
    """
    if not isinstance(time_value, (int, float)) or time_value < 0:
        msg = "'time_value' must be a non-negative number."
        raise ValueError(msg)

    unit_from = unit_from.lower()
    unit_to = unit_to.lower()
    if unit_from not in time_chart or unit_to not in time_chart:
        invalid_unit = unit_from if unit_from not in time_chart else unit_to
        msg = f"Invalid unit {invalid_unit} is not in {', '.join(time_chart)}."
        raise ValueError(msg)

    return round(
        time_value * time_chart[unit_from] * time_chart_inverse[unit_to],
        3,
    )


if __name__ == "__main__":
    import doctest

    doctest.testmod()
    print(f"{convert_time(3600,'seconds', 'hours') = :,}")
    print(f"{convert_time(360, 'days', 'months') = :,}")
    print(f"{convert_time(360, 'months', 'years') = :,}")
    print(f"{convert_time(1, 'years', 'seconds') = :,}")

View on GitHub (pinned to f5988cc097)

Solutions

  1. Use the exact plural keys: seconds, minutes, hours, days, weeks, months, years, decades, centuries.
  2. Build an abbreviation map: {'sec': 'seconds', 'min': 'minutes', 'hr': 'hours', 's': 'seconds', 'h': 'hours'}.
  3. Derive dropdown options from the library's chart (time_chart keys) instead of hand-writing them.

Example fix

# before
convert_time(1, 'sec', 'min')  # ValueError: Invalid unit sec is not in seconds, minutes, ...

# after
ALIASES = {'sec': 'seconds', 'min': 'minutes', 'hr': 'hours', 'day': 'days', 'yr': 'years'}
convert_time(1, ALIASES['sec'], ALIASES['min'])
Defensive patterns

Strategy: validation

Validate before calling

from conversions.time_conversions import time_chart

unit_from = ALIASES.get(unit_from.lower(), unit_from.lower())
unit_to = ALIASES.get(unit_to.lower(), unit_to.lower())
if unit_from not in time_chart or unit_to not in time_chart:
    raise ValueError(f'unsupported time unit(s) {unit_from!r}, {unit_to!r}')
convert_time(value, unit_from, unit_to)

Type guard

from conversions.time_conversions import time_chart

def is_time_unit(u: object) -> bool:
    return isinstance(u, str) and u.lower() in time_chart

Try / catch

try:
    convert_time(v, f, t)
except ValueError as e:
    if 'Invalid unit' in str(e):
        raise UserInputError(f'unknown time unit in {f!r}->{t!r}') from e
    raise

Prevention

When it happens

Trigger: Calling convert_time(1, 'cool', 'century') — note the singular/plural mismatch: 'century' fails, 'centuries' passes; also 'sec', 'min', 'hr', 'ms' abbreviations all fail.

Common situations: Using abbreviated unit names from other libraries (pandas 'T'/'min', dateutil 'H'); singular/plural drift between UI labels and this API; non-English or symbol units ('s', 'h').

Related errors


AI-assisted analysis of TheAlgorithms/Python@f5988cc097 (2026-08-14). Data as JSON: /api/errors/082f8b795aac90d0. Report an issue: GitHub.