python/cpython · error · ValueError

Failed to encode latin1 string when unpickling a time object

Error message

Failed to encode latin1 string when unpickling a time object. pickle.load(data, encoding='latin1') is assumed.

What it means

Raised by time.__new__ during unpickling when the pickle payload's first argument is a 6-character str that cannot be encoded to latin1. Python pickles datetime.time as a byte string; when a pickle created with protocol-level str handling is loaded with an encoding other than latin1 (e.g. pickle.load(data, encoding='utf-8')), the str may contain non-latin1 characters and the reconstruction fails with this explanatory ValueError.

Source

Thrown at Lib/_pydatetime.py:1444

    def __new__(cls, hour=0, minute=0, second=0, microsecond=0, tzinfo=None, *, fold=0):
        """Constructor.

        Arguments:

        hour, minute (required)
        second, microsecond (default to zero)
        tzinfo (default to None)
        fold (keyword only, default to zero)
        """
        if (isinstance(hour, (bytes, str)) and len(hour) == 6 and
            ord(hour[0:1])&0x7F < 24):
            # Pickle support
            if isinstance(hour, str):
                try:
                    hour = hour.encode('latin1')
                except UnicodeEncodeError:
                    # More informative error message.
                    raise ValueError(
                        "Failed to encode latin1 string when unpickling "
                        "a time object. "
                        "pickle.load(data, encoding='latin1') is assumed.")
            self = object.__new__(cls)
            self.__setstate(hour, minute or None)
            self._hashcode = -1
            return self
        hour, minute, second, microsecond, fold = _check_time_fields(
            hour, minute, second, microsecond, fold)
        _check_tzinfo_arg(tzinfo)
        self = object.__new__(cls)
        self._hour = hour
        self._minute = minute
        self._second = second
        self._microsecond = microsecond
        self._tzinfo = tzinfo
        self._hashcode = -1
        self._fold = fold

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Load with pickle.load(f, encoding='latin1') as the message states
  2. Re-serialize the data in a version-neutral format: JSON ISO strings, or pickle.dumps with the highest protocol in Python 3
  3. If the source pickle is corrupt, recover field values and reconstruct time objects explicitly

Example fix

# before
obj = pickle.load(f, encoding='utf-8')

# after
obj = pickle.load(f, encoding='latin1')
Defensive patterns

Strategy: try-catch

Validate before calling

if isinstance(v, str) and any(ord(c) > 255 for c in v[:6]) and len(v) == 6:
    raise ValueError('non-latin1 payload: load the pickle with encoding=latin1')

Try / catch

try:
    obj = pickle.load(f, encoding='latin1')
except ValueError:
    # payload is not a latin1 pickle; retry default or re-raise
    raise

Prevention

When it happens

Trigger: pickle.loads(data, encoding='utf-8') (or pickle.load with a non-latin1 encoding) on a pickle containing a datetime.time; pickles produced by Python 2 and loaded into Python 3 with the wrong encoding argument; hand-crafted time('\\x89\\x00...') str arguments with chars above U+00FF.

Common situations: Migrating Python 2 pickle archives to Python 3 without the documented encoding='latin1' argument; cross-version data pipelines (Redis/database blob storage of pickles); loading old .pkl files with generic unpickle helpers that pass encoding='utf-8'.

Related errors


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