pola-rs/polars · error · ValueError

`format` must be one of {'binary', 'json'}, got {format!r}

Error message

`format` must be one of {'binary', 'json'}, got {format!r}

What it means

`LazyFrame.deserialize` (frame.py:495) reconstructs a `LazyFrame` from serialized plan bytes and dispatches on the `format` argument: `'binary'` maps to `PyLazyFrame.deserialize_binary` and `'json'` to `deserialize_json`. Any other value (pickle, serde, uppercase variants, typos) raises ValueError after the source has been normalized to a file path or `BytesIO` but before deserialization runs.

Source

Thrown at py-polars/src/polars/lazyframe/frame.py:495

        │ i64 │
        ╞═════╡
        │ 6   │
        └─────┘
        """
        if isinstance(source, StringIO):
            source = BytesIO(source.getvalue().encode())
        elif isinstance(source, (str, Path)):
            source = normalize_filepath(source)
        elif isinstance(source, bytes):
            source = io.BytesIO(source)

        if format == "binary":
            deserializer = PyLazyFrame.deserialize_binary
        elif format == "json":
            deserializer = PyLazyFrame.deserialize_json
        else:
            msg = f"`format` must be one of {{'binary', 'json'}}, got {format!r}"
            raise ValueError(msg)

        return cls._from_pyldf(deserializer(source))

    @property
    def columns(self) -> list[str]:
        """
        Get the column names.

        Returns
        -------
        list of str
            A list containing the name of each column in order.

        Warnings
        --------
        Determining the column names of a LazyFrame requires resolving its schema,
        which is a potentially expensive operation.
        Using :meth:`collect_schema` is the idiomatic way of resolving the schema.

View on GitHub (pinned to df599052da)

Solutions

  1. Use `'binary'` (default, compact) or `'json'` (exact lowercase) — and match the format used to serialize: `lf.serialize(format='json')` pairs with `deserialize(format='json')`
  2. If the format string is dynamic, validate it against `{'binary','json'}` before calling
  3. Store plans with `lf.serialize()` and rely on the default 'binary' to avoid mismatches

Example fix

# before
lf2 = pl.LazyFrame.deserialize(data, format='pickle')  # ValueError

# after
lf2 = pl.LazyFrame.deserialize(data, format='binary')
# round-trip:
pl.LazyFrame.deserialize(lf.serialize(format='json'), format='json')
Defensive patterns

Strategy: validation

Validate before calling

DESERIALIZE_FORMATS = frozenset({'binary', 'json'})

def deserialize_plan(data, fmt: str = 'binary') -> pl.LazyFrame:
    if fmt not in DESERIALIZE_FORMATS:
        raise ValueError(f'format must be one of {sorted(DESERIALIZE_FORMATS)}, got {fmt!r}')
    return pl.LazyFrame.deserialize(data, format=fmt)

Type guard

from typing import TypeGuard

def is_deserialize_format(value: object) -> TypeGuard[str]:
    return value in ('binary', 'json')

Try / catch

try:
    lf = pl.LazyFrame.deserialize(data, format=fmt)
except ValueError as e:
    if 'format' in str(e):
        lf = pl.LazyFrame.deserialize(data, format='binary')
    else:
        raise

Prevention

When it happens

Trigger: `pl.LazyFrame.deserialize(data, format='pickle')`, `format='JSON'`, `format='json '` (whitespace), or any string not exactly `'binary'` or `'json'`. `data` itself may be `str`/`Path`/`bytes`/binary IO; only `format` is validated here.

Common situations: Hand-rolled persistence of query plans with a format field stored in a database; mixing up DataFrame serialization formats (`write_ipc`/feather) with LazyFrame plan formats; config-driven format parameters passed through unvalidated.

Related errors


AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16). Data as JSON: /api/errors/e012795cd4cc2ed8. Report an issue: GitHub.