pola-rs/polars · error · TypeError

did not expect type: {qualified_type_name(elems[0])!r} in `c

Error message

did not expect type: {qualified_type_name(elems[0])!r} in `concat`

What it means

Raised by pl.concat when the input list is not a homogeneous sequence of DataFrame, LazyFrame, Series, or Expr. The dispatcher tests each type in turn (is_non_empty_sequence_of); when all fail it raises TypeError naming the qualified type of elems[0], e.g. 'builtins.str', 'numpy.ndarray', 'NoneType'.

Source

Thrown at py-polars/src/polars/functions/eager.py:375

                )
            )
        else:
            allowed = ", ".join(repr(m) for m in get_args(ConcatMethod))
            msg = f"LazyFrame `how` must be one of {{{allowed}}}, got {how!r}"
            raise ValueError(msg)

    elif is_non_empty_sequence_of(elems, pl.Series):
        if how == "vertical":
            out = wrap_s(plr.concat_series(elems))
        else:
            msg = "Series only supports 'vertical' concat strategy"
            raise ValueError(msg)

    elif is_non_empty_sequence_of(elems, pl.Expr):
        return wrap_expr(plr.concat_expr([e._pyexpr for e in elems], rechunk))
    else:
        msg = f"did not expect type: {qualified_type_name(elems[0])!r} in `concat`"
        raise TypeError(msg)

    if rechunk:
        return out.rechunk()
    return out


def union(
    items: Iterable[PolarsType],
    *,
    how: ConcatMethod = "vertical",
    strict: bool | None = None,
) -> PolarsType:
    """
    Combine multiple DataFrames, LazyFrames, or Series into a single object.

    .. warning::
        This function does not guarantee any specific ordering of rows in the result.
        If you need predictable row ordering, use `pl.concat()` instead.

View on GitHub (pinned to df599052da)

Solutions

  1. Make all elements the same type: collect LazyFrames (lf.collect()) or make DataFrames lazy (df.lazy())
  2. Wrap mapping values: pl.concat(list(frames_by_name.values()))
  3. Materialize generators with list() first so type dispatch inspects real items and mixed types become visible

Example fix

# before
pl.concat([df1, lf2])        # TypeError
pl.concat(frames_by_name)     # dict -> TypeError

# after
pl.concat([df1, lf2.collect()])
pl.concat(list(frames_by_name.values()))
Defensive patterns

Strategy: type-guard

Type guard

def is_concatable(items) -> bool:
    items = list(items)
    if not items:
        return False
    first = type(items[0])
    return first in (pl.DataFrame, pl.LazyFrame, pl.Series, pl.Expr) and all(
        type(e) is first for e in items
    )

Prevention

When it happens

Trigger: pl.concat([df, lf]) mixing DataFrame and LazyFrame; pl.concat(['a', 'b']); passing a dict or dict.keys() instead of its values; a numpy array or list-of-lists; a generator that yields non-frame objects.

Common situations: Passing a dict of frames instead of list(d.values()); mixing eager frames (read_parquet) with lazy ones (scan_parquet) from different pipeline stages; forgetting list() around a generator whose content is unknown; passing raw Python containers where frames were expected.

Related errors


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