python/cpython · error · TypeError

Argument must be a str

Error message

Argument must be a str

What it means

Raised by date.fromisoformat() when the argument is not a str instance. The parser handles only the ISO 8601 date text format; bytes, bytearrays, or other objects must be decoded first. This is a deliberate TypeError separating 'wrong type' from 'wrong format' (which raises ValueError).

Source

Thrown at Lib/_pydatetime.py:1054

        t = _time.time()
        return cls.fromtimestamp(t)

    @classmethod
    def fromordinal(cls, n):
        """Construct a date from a proleptic Gregorian ordinal.

        January 1 of year 1 is day 1.  Only the year, month and day are
        non-zero in the result.
        """
        y, m, d = _ord2ymd(n)
        return cls(y, m, d)

    @classmethod
    def fromisoformat(cls, date_string):
        """Construct a date from a string in ISO 8601 format."""

        if not isinstance(date_string, str):
            raise TypeError('Argument must be a str')

        if not date_string.isascii():
            raise ValueError('Argument must be an ASCII str')

        if len(date_string) not in (7, 8, 10):
            raise ValueError(f'Invalid isoformat string: {date_string!r}')

        try:
            return cls(*_parse_isoformat_date(date_string))
        except Exception:
            raise ValueError(f'Invalid isoformat string: {date_string!r}')

    @classmethod
    def fromisocalendar(cls, year, week, day):
        """Construct a date from the ISO year, week number and weekday.

        This is the inverse of the date.isocalendar() function"""
        return cls(*_isoweek_to_gregorian(year, week, day))

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Decode first: date.fromisoformat(raw.decode('utf-8'))
  2. Check isinstance(s, str) at the ingestion boundary
  3. For full ISO 8601 including 'Z' and offsets on datetimes, use datetime.fromisoformat (3.11+) or dateutil

Example fix

# before
d = date.fromisoformat(body['date'])  # bytes from request
# after
d = date.fromisoformat(body['date'].decode('utf-8'))
Defensive patterns

Strategy: type-guard

Validate before calling

if not isinstance(s, str):
    s = s.decode('utf-8') if isinstance(s, (bytes, bytearray)) else str(s)
d = date.fromisoformat(s)

Type guard

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

Prevention

When it happens

Trigger: date.fromisoformat(b'2024-01-01'); passing a pathlib-derived bytes value or a value from a JSON parser that yields non-str; fromisoformat(None).

Common situations: Feeding bytes read from sockets/files or from Redis/kafka consumers directly; mixed str/bytes pipelines after a Python 2→3 migration; passing user input that arrived as bytes from a web framework.

Related errors


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