python/cpython · error · TypeError

fromisoformat: argument must be str

Error message

fromisoformat: argument must be str

What it means

Raised by time.fromisoformat() when the argument is not a str instance. The parser accepts only text in ISO 8601 time formats; bytes, memoryview, or other objects are rejected up front with a TypeError naming the requirement.

Source

Thrown at Lib/_pydatetime.py:1638

        The optional argument timespec specifies the number of additional
        terms of the time to include. Valid options are 'auto', 'hours',
        'minutes', 'seconds', 'milliseconds' and 'microseconds'.
        """
        s = _format_time(self._hour, self._minute, self._second,
                          self._microsecond, timespec)
        tz = self._tzstr()
        if tz:
            s += tz
        return s

    __str__ = isoformat

    @classmethod
    def fromisoformat(cls, time_string):
        """Construct a time from a string in one of the ISO 8601 formats."""
        if not isinstance(time_string, str):
            raise TypeError('fromisoformat: argument must be str')

        # The spec actually requires that time-only ISO 8601 strings start with
        # T, but the extended format allows this to be omitted as long as there
        # is no ambiguity with date strings.
        time_string = time_string.removeprefix('T')

        try:
            time_components, _, error_from_components, error_from_tz = (
                _parse_isoformat_time(time_string)
            )
        except ValueError:
            raise ValueError(
                f'Invalid isoformat string: {time_string!r}') from None
        else:
            if error_from_tz:
                raise error_from_tz
            if error_from_components:
                raise ValueError(

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Decode bytes first: time.fromisoformat(raw.decode('utf-8'))
  2. Skip parsing when the value is already a time instance: isinstance(v, time)
  3. Guard optional fields: if v is not None: t = time.fromisoformat(v)

Example fix

# before
t = time.fromisoformat(b'12:30:00')

# after
t = time.fromisoformat(b'12:30:00'.decode('ascii'))
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(v, str):
    if isinstance(v, (bytes, bytearray)):
        v = v.decode('utf-8')
    elif v is None:
        raise ValueError('missing time field')
    else:
        raise TypeError(f'cannot parse {type(v).__name__} as time')
t = time.fromisoformat(v)

Type guard

def is_parseable_str(v) -> bool:
    return isinstance(v, str)

Try / catch

try:
    t = time.fromisoformat(v)
except TypeError:
    t = time.fromisoformat(v.decode('utf-8'))  # only when bytes was plausible

Prevention

When it happens

Trigger: time.fromisoformat(b'12:00:00'); time.fromisoformat(memoryview(b'12:00')); passing a datetime.time object itself; passing None as a default when a config field is missing.

Common situations: Values read from sockets/files as bytes; database or JSON fields already parsed into time objects; optional fields where the caller forwards None instead of skipping the parse.

Related errors


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