← Back to PR Bug Fix Database
7
High
PR-scikit-learn-34258

Fix: Improve error message when polars LazyFrame is passed to check_array

HighRepo: scikit-learn/scikit-learnDate: July 14, 2026
PR Fixscikit-learnBug FixEdge Case

// The Bug

Fixed scikit-learn/scikit-learn#34258 — 6 line bug-fix adding a clear TypeError when a polars LazyFrame (instead of DataFrame) hits check_array.

Repository
scikit-learn/scikit-learn
Issue
Status
PR-submitted
Fix Scope
6 lines changed in `sklearn/utils/validation.py`
Description
Improve error message when polars LazyFrame is passed to check_array

// Root Cause

The edge case in `def check_array(` at `sklearn/utils/validation.py` causes incorrect behavior when a specific input condition is met. In Python, this pattern is easy to miss because standard test suites rarely cover every boundary condition.

The specific scenario: polars has two fundamentally different DataFrame types — `DataFrame` (eager, materialized in memory) and `LazyFrame` (deferred, query plan only). `check_array` already handled eager polars DataFrames through the existing `numpy_wrapper` interop layer, but `LazyFrame` passed through silently and then failed with an opaque error deep in the validation pipeline. Users got a cryptic traceback about missing attributes instead of a clear message telling them to call `.collect()` first.

The fix is a focused change — it addresses exactly the failing condition without refactoring surrounding code. This minimizes the risk of introducing new bugs.

**Impact**: The bug affects users who pass polars LazyFrames to scikit-learn estimators. With the growing adoption of polars as a pandas alternative in the data science ecosystem, this edge case becomes more common. The fix transforms an opaque internal error into a clear actionable message.

// The Fix

Diff showing the exact changes made to fix the bug.

@@ -864,6 +864,12 @@ def check_array(
             "https://numpy.org/doc/stable/reference/generated/numpy.matrix.html"
         )

+    if nw.dependencies.is_into_lazyframe(array):
+        raise TypeError(
+            "A polars LazyFrame was passed, but lazy dataframes are not supported."
+            " Use '.collect()' to convert it to a polars DataFrame."
+        )
+
     xp, is_array_api_compliant = get_namespace(array)

     # store reference to original array to check if copy is needed when

// Pattern & Takeaways

**Pattern**: Edge case in `def check_array(` — the Python code path was not tested with the specific input that triggers the failure. The focused fix demonstrates that the most reliable approach is to change the minimum necessary code.

The deeper lesson is about **defensive validation at the API boundary**. When a function accepts a union type (DataFrame, array-like, sparse matrix), each variant needs its own fast-fail check before entering shared processing logic. Without these early guards, a type that is almost-but-not-quite compatible (like LazyFrame vs DataFrame) passes the initial type check and fails confusingly later. The fix pattern — detect the near-miss type and raise a specific actionable error — is portable to any API that accepts multiple input formats.

**Key insight**: The most predictable bugs are edge cases at input boundaries where types are similar but semantically different. Code review should focus on: (1) What near-miss types could arrive? (2) Does each produce a clear error message? (3) Can the error suggest the correct fix? A good TypeError tells the caller what they did wrong *and* what to do instead.