python/cpython · error · ValueError

Failed to encode latin1 string when unpickling a date object

Error message

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

What it means

Raised by date.__new__ during unpickling: the 4-byte pickled date string could not be encoded to latin1. Pickles created with protocol < 2 (or loaded with encoding='latin1' semantics) store dates as 4-byte strings; if the bytes contain non-latin1-encodable code points, the string is corrupt and reconstruction fails with this ValueError instead of a cryptic UnicodeEncodeError.

Source

Thrown at Lib/_pydatetime.py:1007

    __slots__ = '_year', '_month', '_day', '_hashcode'

    def __new__(cls, year, month=None, day=None):
        """Constructor.

        Arguments:

        year, month, day (required, base 1)
        """
        if (month is None and
            isinstance(year, (bytes, str)) and len(year) == 4 and
            1 <= ord(year[2:3]) <= 12):
            # Pickle support
            if isinstance(year, str):
                try:
                    year = year.encode('latin1')
                except UnicodeEncodeError:
                    # More informative error message.
                    raise ValueError(
                        "Failed to encode latin1 string when unpickling "
                        "a date object. "
                        "pickle.load(data, encoding='latin1') is assumed.")
            self = object.__new__(cls)
            self.__setstate(year)
            self._hashcode = -1
            return self
        year, month, day = _check_date_fields(year, month, day)
        self = object.__new__(cls)
        self._year = year
        self._month = month
        self._day = day
        self._hashcode = -1
        return self

    # Additional constructors

    @classmethod

View on GitHub (pinned to bc6749cc3b)

Solutions

  1. Load legacy pickles with pickle.load(f, encoding='latin1') as the message instructs
  2. Regenerate the pickle from the original data source if it is corrupt
  3. Prefer pickle protocol >= 2 (or JSON) for cross-version/transport-safe serialization

Example fix

# before
obj = pickle.load(f)  # protocol-0 pickle from Python 2
# after
obj = pickle.load(f, encoding='latin1')
Defensive patterns

Strategy: try-catch

Try / catch

try:
    obj = pickle.loads(data)
except ValueError as e:
    if 'latin1' in str(e):
        obj = pickle.loads(data, encoding='latin1')
    else:
        raise

Prevention

When it happens

Trigger: pickle.load on data not produced by pickle (truncated or tampered date pickles); loading protocol-0/1 pickles across encodings where the 4-char date string was damaged; hand-crafting date(string) calls that match the pickle shape (len 4, month byte 1..12).

Common situations: Reading pickles from untrusted or corrupted sources; pickles transferred through channels that mangled non-ASCII bytes (e.g. decoded as UTF-8 then re-encoded); legacy Python 2 pickles loaded with wrong encoding parameter.

Related errors


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