{"record":{"id":"54986bba5064ae78","repo":"pola-rs/polars","slug":"input-frames-must-be-of-a-consistent-type-all-laz","errorCode":null,"errorMessage":"input frames must be of a consistent type (all LazyFrame or all DataFrame)","messagePattern":"input frames must be of a consistent type \\(all LazyFrame or all DataFrame\\)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"py-polars/src/polars/functions/eager.py","lineNumber":978,"sourceCode":"    ├╌╌╌╌╌╌╌┤\n    │ 167.5 │\n    ├╌╌╌╌╌╌╌┤\n    │ 47.0  │\n    └───────┘\n    \"\"\"  # noqa: W505\n    if not frames:\n        return []\n\n    if len(frames) == 1 and not isinstance(frames[0], (pl.DataFrame, pl.LazyFrame)):\n        frames = frames[0]  # type: ignore[assignment]\n    if isinstance(frames, (Generator, Iterator)):\n        frames = tuple(frames)\n\n    if len({type(f) for f in frames}) != 1:\n        msg = (\n            \"input frames must be of a consistent type (all LazyFrame or all DataFrame)\"\n        )\n        raise TypeError(msg)\n\n    eager = isinstance(frames[0], pl.DataFrame)\n    on = [on] if (isinstance(on, str) or not isinstance(on, Sequence)) else on\n    align_on = [(c.meta.output_name() if isinstance(c, pl.Expr) else c) for c in on]\n\n    # create aligned master frame (this is the most expensive part; after\n    # we just select out the columns representing the component frames)\n    idx_frames = [(idx, frame.lazy()) for idx, frame in enumerate(frames)]  # type: ignore[union-attr]\n    alignment_frame = _alignment_join(\n        *idx_frames, align_on=align_on, how=how, descending=descending, eager=eager\n    )\n\n    # select-out aligned components from the master frame\n    aligned_cols = set(alignment_frame.collect_schema())\n    aligned_frames = []\n    for idx, lf in idx_frames:\n        sfx = f\":{idx}\"\n        df_cols = [","sourceCodeStart":960,"sourceCodeEnd":996,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/py-polars/src/polars/functions/eager.py#L960-L996","documentation":"Raised by align_frames when the frames are not all the same concrete type. The check compares {type(f) for f in frames}; any mix — typically pl.DataFrame from read_* combined with pl.LazyFrame from scan_* — raises TypeError. A sole non-frame argument is first unpacked as an iterable of frames.","triggerScenarios":"pl.align_frames(df1, lf2, on='ts'); a list built partly from read_parquet (eager) and partly from scan_parquet (lazy); a generator mixing collected and scanned frames.","commonSituations":"Pipelines that scan large files lazily but read small lookup tables eagerly; helpers that collect some frames for size checks and pass others through lazily.","solutions":["Normalize to one type: apply .lazy() to every frame (returns LazyFrames) or .collect() to every frame (returns DataFrames)","Pick one execution model per pipeline stage and enforce it at the boundary","If only schemas were needed from the lazy frames, use collect_schema() and keep data eager"],"exampleFix":"# before\npl.align_frames(df1, lf2, on='ts', how='inner')  # TypeError\n\n# after (all lazy)\npl.align_frames(df1.lazy(), lf2, on='ts', how='inner')","handlingStrategy":"type-guard","validationCode":"if len({type(f) for f in frames}) != 1:\n    frames = [f.lazy() for f in frames]  # normalize to LazyFrame\naligned = pl.align_frames(*frames, on=on, how=how)","typeGuard":"def uniform_frames(frames) -> bool:\n    return (\n        bool(frames)\n        and len({type(f) for f in frames}) == 1\n        and isinstance(frames[0], (pl.DataFrame, pl.LazyFrame))\n    )","tryCatchPattern":null,"preventionTips":["Pick one execution model (lazy or eager) per pipeline stage and enforce it","Wrap frame producers so they always return LazyFrame (or always DataFrame)"],"tags":["polars","align-frames","type-check","lazy-eager-mix"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}