{"record":{"id":"9c31e11494dc1c1a","repo":"pola-rs/polars","slug":"series-only-supports-vertical-concat-strategy","errorCode":null,"errorMessage":"Series only supports 'vertical' concat strategy","messagePattern":"Series only supports 'vertical' concat strategy","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/functions/eager.py","lineNumber":369,"sourceCode":"        elif how == \"horizontal_extend\":\n            return wrap_ldf(\n                plr.concat_lf_horizontal(\n                    elems,\n                    parallel=parallel,\n                    strict=False,\n                )\n            )\n        else:\n            allowed = \", \".join(repr(m) for m in get_args(ConcatMethod))\n            msg = f\"LazyFrame `how` must be one of {{{allowed}}}, got {how!r}\"\n            raise ValueError(msg)\n\n    elif is_non_empty_sequence_of(elems, pl.Series):\n        if how == \"vertical\":\n            out = wrap_s(plr.concat_series(elems))\n        else:\n            msg = \"Series only supports 'vertical' concat strategy\"\n            raise ValueError(msg)\n\n    elif is_non_empty_sequence_of(elems, pl.Expr):\n        return wrap_expr(plr.concat_expr([e._pyexpr for e in elems], rechunk))\n    else:\n        msg = f\"did not expect type: {qualified_type_name(elems[0])!r} in `concat`\"\n        raise TypeError(msg)\n\n    if rechunk:\n        return out.rechunk()\n    return out\n\n\ndef union(\n    items: Iterable[PolarsType],\n    *,\n    how: ConcatMethod = \"vertical\",\n    strict: bool | None = None,\n) -> PolarsType:","sourceCodeStart":351,"sourceCodeEnd":387,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/functions/eager.py#L351-L387","documentation":"Raised by pl.concat when every element of the input is a pl.Series but `how` is not 'vertical'. A Series is a single 1-D column, so there is no horizontal, diagonal, or aligned layout to concatenate it into. The Python layer validates this before any Rust concat code runs.","triggerScenarios":"pl.concat([s1, s2], how='horizontal') (or 'diagonal', 'vertical_relaxed', 'align', 'align_full', ...) where all elements are pl.Series. Typically generic helper code forwards the same `how` string regardless of whether it was handed Series or DataFrames.","commonSituations":"Helper functions that accept 'frames or series' and pass a caller-supplied strategy straight through; refactors that turn a list of one-column DataFrames into a list of Series; copy-pasting a DataFrame concat call onto Series inputs.","solutions":["Use how='vertical' (the default) for Series: pl.concat([s1, s2])","To place Series side by side as columns, build a DataFrame: pl.DataFrame([s1, s2]) or pl.concat([s1.to_frame(), s2.to_frame()], how='horizontal')","For supertype casting (vertical_relaxed), cast the Series yourself first with s.cast(...) and then concat vertically"],"exampleFix":"# before\nout = pl.concat([s1, s2], how='horizontal')  # ValueError\n\n# after (side-by-side columns)\nout = pl.DataFrame([s1, s2])\n# or valid vertical stacking\nout = pl.concat([s1, s2])","handlingStrategy":"validation","validationCode":"items = list(items)\nif all(isinstance(e, pl.Series) for e in items) and how != 'vertical':\n    raise ValueError(f'Series inputs only support how=vertical, got {how!r}')\nout = pl.concat(items, how=how)","typeGuard":"def is_series_list(items) -> bool:\n    items = list(items)\n    return bool(items) and all(isinstance(e, pl.Series) for e in items)","tryCatchPattern":null,"preventionTips":["Type helper parameters as Sequence[pl.Series] and hard-code how='vertical'","Annotate how as ConcatMethod so static type checkers flag invalid literals"],"tags":["polars","concat","series","input-validation"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}