{"record":{"id":"6a8f34dbdc5f177a","repo":"python/cpython","slug":"fromisoformat-argument-must-be-str","errorCode":null,"errorMessage":"fromisoformat: argument must be str","messagePattern":"fromisoformat: argument must be str","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":1638,"sourceCode":"\n        The optional argument timespec specifies the number of additional\n        terms of the time to include. Valid options are 'auto', 'hours',\n        'minutes', 'seconds', 'milliseconds' and 'microseconds'.\n        \"\"\"\n        s = _format_time(self._hour, self._minute, self._second,\n                          self._microsecond, timespec)\n        tz = self._tzstr()\n        if tz:\n            s += tz\n        return s\n\n    __str__ = isoformat\n\n    @classmethod\n    def fromisoformat(cls, time_string):\n        \"\"\"Construct a time from a string in one of the ISO 8601 formats.\"\"\"\n        if not isinstance(time_string, str):\n            raise TypeError('fromisoformat: argument must be str')\n\n        # The spec actually requires that time-only ISO 8601 strings start with\n        # T, but the extended format allows this to be omitted as long as there\n        # is no ambiguity with date strings.\n        time_string = time_string.removeprefix('T')\n\n        try:\n            time_components, _, error_from_components, error_from_tz = (\n                _parse_isoformat_time(time_string)\n            )\n        except ValueError:\n            raise ValueError(\n                f'Invalid isoformat string: {time_string!r}') from None\n        else:\n            if error_from_tz:\n                raise error_from_tz\n            if error_from_components:\n                raise ValueError(","sourceCodeStart":1620,"sourceCodeEnd":1656,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pydatetime.py#L1620-L1656","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Decode bytes first: time.fromisoformat(raw.decode('utf-8'))","Skip parsing when the value is already a time instance: isinstance(v, time)","Guard optional fields: if v is not None: t = time.fromisoformat(v)"],"exampleFix":"# before\nt = time.fromisoformat(b'12:30:00')\n\n# after\nt = time.fromisoformat(b'12:30:00'.decode('ascii'))","handlingStrategy":"type-guard","validationCode":"if not isinstance(v, str):\n    if isinstance(v, (bytes, bytearray)):\n        v = v.decode('utf-8')\n    elif v is None:\n        raise ValueError('missing time field')\n    else:\n        raise TypeError(f'cannot parse {type(v).__name__} as time')\nt = time.fromisoformat(v)","typeGuard":"def is_parseable_str(v) -> bool:\n    return isinstance(v, str)","tryCatchPattern":"try:\n    t = time.fromisoformat(v)\nexcept TypeError:\n    t = time.fromisoformat(v.decode('utf-8'))  # only when bytes was plausible","preventionTips":["Decode bytes at the I/O boundary","Skip already-parsed time objects via isinstance checks","Guard optional fields for None before parsing"],"tags":["datetime","time","typeerror","fromisoformat","bytes"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}