python/cpython · error · ValueError

Isoformat time too short

Error message

Isoformat time too short

What it means

_parse_isoformat_time requires at least two characters ('HH') before doing anything; a time portion shorter than 2 chars — empty, a lone digit, or a string where the tz search consumed everything — raises ValueError('Isoformat time too short').

Source

Thrown at Lib/_pydatetime.py:449

            len_remainder = len_str - pos

            if len_remainder >= 6:
                to_parse = 6
            else:
                to_parse = len_remainder

            time_comps[3] = int(tstr[pos:(pos+to_parse)])
            if to_parse < 6:
                time_comps[3] *= _FRACTION_CORRECTION[to_parse-1]

    return time_comps

def _parse_isoformat_time(tstr):
    # Format supported is HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]
    len_str = len(tstr)
    if len_str < 2:
        raise ValueError("Isoformat time too short")

    # This is equivalent to re.search('[+-Z]', tstr), but faster
    tz_pos = (tstr.find('-') + 1 or tstr.find('+') + 1 or tstr.find('Z') + 1)
    timestr = tstr[:tz_pos-1] if tz_pos > 0 else tstr

    time_comps = _parse_hh_mm_ss_ff(timestr)

    hour, minute, second, microsecond = time_comps
    became_next_day = False
    error_from_components = False
    error_from_tz = None
    if (hour == 24):
        if all(time_comp == 0 for time_comp in time_comps[1:]):
            hour = 0
            time_comps[0] = hour
            became_next_day = True
        else:
            error_from_components = True

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Omit the 'T' and time entirely for date-only values: use date.fromisoformat or datetime.fromisoformat('2021-01-01')
  2. Guard empty optional parts: parse time only if time_part, else midnight: datetime.combine(d, time())
  3. Validate with len check or regex before calling fromisoformat

Example fix

// before
dt = datetime.fromisoformat(f"{d_str}T{t_str}")  # t_str == '' -> ValueError

# after
from datetime import datetime, time
dt = (datetime.fromisoformat(f"{d_str}T{t_str}") if t_str
      else datetime.combine(datetime.fromisoformat(d_str).date(), time()))
Defensive patterns

Strategy: validation

Validate before calling

def join_iso(d_str: str, t_str: str) -> str:
    if not t_str:
        return d_str  # date-only is valid input to datetime.fromisoformat
    return f'{d_str}T{t_str}'

Type guard

def time_part_present(t: str) -> bool:
    return len(t) >= 2

Prevention

When it happens

Trigger: datetime.fromisoformat('2021-01-01T') (empty time after separator); '2021-01-01T1'; a string like '12+01:00' passed as a bare time where tz_pos splits leave '<2' chars; fromisoformat on a date-only string via datetime (older versions error differently, some paths land here).

Common situations: Splitting 'dateTtime' on 'T' and feeding the empty right half; optional time fields defaulting to '' instead of None; templates emitting the separator when the time part is absent.

Related errors


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/352571ee6b010c77. Report an issue: GitHub.