pola-rs/polars · error

passing Expr objects to the DataFrame constructor is not sup

Error message

passing Expr objects to the DataFrame constructor is not supported

Hint: Try evaluating the expression first using `select`, or if you meant to create an Object column containing expressions, pass a list of Expr objects instead.

What it means

When expanding dict data for DataFrame construction, polars refuses values that are polars Expressions: an Expr is a lazy, context-dependent object with no data to place in a column, so the constructor cannot materialize it. The error tells you to evaluate the expression in a frame context (select/with_columns) or, if an Object column of expressions is genuinely intended, to wrap the Exprs in a list.

Source

Thrown at py-polars/src/polars/_utils/construction/dataframe.py:355

def _expand_dict_values(
    data: Mapping[str, ArrayLike | NonNestedLiteral | None],
    *,
    schema_overrides: SchemaDict | None = None,
    strict: bool = True,
    order: Sequence[str] | None = None,
    nan_to_null: bool = False,
) -> dict[str, Series]:
    """Expand any scalar values in dict data (propagate literal as array)."""
    updated_data = {}
    if data:
        if any(isinstance(val, pl.Expr) for val in data.values()):
            msg = (
                "passing Expr objects to the DataFrame constructor is not supported"
                "\n\nHint: Try evaluating the expression first using `select`,"
                " or if you meant to create an Object column containing expressions,"
                " pass a list of Expr objects instead."
            )
            raise TypeError(msg)

        dtypes = schema_overrides or {}
        data = _expand_dict_data(data, dtypes, strict=strict)
        array_len = max((arrlen(val) or 0) for val in data.values())
        if array_len > 0:
            for name, val in data.items():
                dtype = dtypes.get(name)
                if isinstance(val, dict) and dtype != Struct:
                    vdf = pl.DataFrame(val, strict=strict)
                    if (
                        vdf.height == 1
                        and array_len > 1
                        and all(not d.is_nested() for d in vdf.schema.values())
                    ):
                        s_vals = {
                            nm: vdf[nm].extend_constant(v, n=(array_len - 1))
                            for nm, v in val.items()
                        }

View on GitHub (pinned to df599052da)

Solutions

  1. Evaluate against an existing frame: `df.select((pl.col("a") + 1).alias("x"))` or `df.with_columns(...)`
  2. For constants use plain Python scalars or lists: `pl.DataFrame({"x": [3]})`
  3. If you truly want an Object column storing Expr objects (meta-programming/tests), wrap in a list: `pl.DataFrame({"e": [pl.col("a")]})`

Example fix

# before
pl.DataFrame({"x": pl.col("a") * 2})
# TypeError: passing Expr objects to the DataFrame constructor is not supported

# after — evaluate in a frame context
df.select((pl.col("a") * 2).alias("x"))

# after — constant column
pl.DataFrame({"x": [3]})

# after — deliberate Object column of Exprs
pl.DataFrame({"exprs": [pl.col("a") * 2]})
Defensive patterns

Strategy: type-guard

Validate before calling

import polars as pl

def dict_is_constructible(data: dict) -> bool:
    return not any(isinstance(v, pl.Expr) for v in data.values())

assert dict_is_constructible({"x": pl.col("a")}) is False

Type guard

import polars as pl

def contains_expr(data: dict) -> bool:
    """True if any dict value is a polars Expr (which the constructor rejects)."""
    return any(isinstance(v, pl.Expr) for v in data.values())

Try / catch

try:
    df = pl.DataFrame(data)
except TypeError as e:
    if "Expr objects" not in str(e):
        raise
    df = base_df.select([v.alias(k) for k, v in data.items()])  # evaluate in frame context

Prevention

When it happens

Trigger: `pl.DataFrame({"x": pl.col("a") + 1})` or `pl.DataFrame({"x": pl.lit(3)})` — any dict value that is a `pl.Expr` instance. Typical when porting pandas-style code where scalar/vector expressions were passed to the constructor.

Common situations: Porting `pd.DataFrame({"x": df["a"] + 1})` habits to polars; building fixtures dynamically; assuming pl.lit works as an inline constant in constructors (use plain Python scalars instead).

Related errors


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