{"record":{"id":"8db2e31090dca95f","repo":"python/cpython","slug":"bad-tzinfo-state-arg","errorCode":null,"errorMessage":"bad tzinfo state arg","messagePattern":"bad tzinfo state arg","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/_pydatetime.py","lineNumber":1758,"sourceCode":"\n    # Pickle support.\n\n    def _getstate(self, protocol=3):\n        us2, us3 = divmod(self._microsecond, 256)\n        us1, us2 = divmod(us2, 256)\n        h = self._hour\n        if self._fold and protocol > 3:\n            h += 128\n        basestate = bytes([h, self._minute, self._second,\n                           us1, us2, us3])\n        if self._tzinfo is None:\n            return (basestate,)\n        else:\n            return (basestate, self._tzinfo)\n\n    def __setstate(self, string, tzinfo):\n        if tzinfo is not None and not isinstance(tzinfo, _tzinfo_class):\n            raise TypeError(\"bad tzinfo state arg\")\n        h, self._minute, self._second, us1, us2, us3 = string\n        if h > 127:\n            self._fold = 1\n            self._hour = h - 128\n        else:\n            self._fold = 0\n            self._hour = h\n        self._microsecond = (((us1 << 8) | us2) << 8) | us3\n        self._tzinfo = tzinfo\n\n    def __reduce_ex__(self, protocol):\n        return (self.__class__, self._getstate(protocol))\n\n    def __reduce__(self):\n        return self.__reduce_ex__(2)\n\n_time_class = time  # so functions w/ args named \"time\" can get at the class\n","sourceCodeStart":1740,"sourceCodeEnd":1776,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_pydatetime.py#L1740-L1776","documentation":"Raised by time.__setstate (pickle reconstruction) when the second state element, the tzinfo, is neither None nor a tzinfo instance. The 6-byte base state is unpacked first, then the tzinfo slot is type-checked; passing a string, a timezone name, or an arbitrary object as the tzinfo component fails with this TypeError. It guards against corrupted or hand-built pickle states.","triggerScenarios":"Constructing time via its pickle form with a bad second argument, e.g. time(b'\\x0c\\x00\\x00\\x00\\x00\\x00', 'UTC'); __setstate__ invoked with a state tuple whose element 1 is a str offset like '+05:00'; custom __reduce_ex__ implementations on subclasses that emit a non-tzinfo object.","commonSituations":"Hand-crafted or manipulated pickles; subclass overrides of __reduce__/__getstate__ that replace the tzinfo with a serializable surrogate (name string) and forget to restore the object on load; pickle round-trips through frameworks that rewrite state tuples.","solutions":["Keep tzinfo objects (or None) in the state; serialize the zone name separately and rebuild via zoneinfo.ZoneInfo(name) after loading","Remove custom __reduce_ex__ overrides that mangle the state layout","If subclassing time, delegate pickling to the parent and only add picklable attributes"],"exampleFix":"# before\nclass T(time):\n    def __reduce__(self):\n        return (time, (self._getstate()[0], 'UTC'))  # str tzinfo -> TypeError on load\n\n# after\nfrom zoneinfo import ZoneInfo\nclass T(time):\n    def __reduce__(self):\n        state, tz = self._getstate()\n        tz = tz if tz is None else tz  # keep real tzinfo object\n        return (time, (state, tz))","handlingStrategy":"validation","validationCode":"from datetime import tzinfo as _tz\ndef valid_time_state(state):\n    tz = state[1] if len(state) > 1 else None\n    return tz is None or isinstance(tz, _tz)","typeGuard":"from datetime import tzinfo as _tz\n\ndef is_valid_tz_arg(v) -> bool:\n    return v is None or isinstance(v, _tz)","tryCatchPattern":"try:\n    obj = pickle.loads(data)\nexcept TypeError as e:\n    if 'bad tzinfo state arg' in str(e):\n        raise RuntimeError('corrupt or rewritten pickle state for datetime.time') from e\n    raise","preventionTips":["Do not override time's pickle methods unless you preserve the exact state layout","Serialize zone names separately and rebuild tzinfo with zoneinfo on load","Treat hand-edited pickle payloads as untrusted input; validate state shape before __setstate__"],"tags":["datetime","time","pickle","typeerror","tzinfo-state"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}