Surfaced by the GPU lane of #1819 on the dgx GB10
(graphistry/test-rapids-official:26.02-gfql-polars, polars 1.35.2). Worked around there, but
the underlying hazard is general and worth its own record.
What happens
A grouped min()/max() over a Categorical column makes polars 1.35.2 panic in its Rust core:
thread 'polars-2' panicked at crates/polars-core/src/series/implementations/categorical.rs:350:1:
not implemented
...
E pyo3_runtime.PanicException: not implemented
polars/lazyframe/frame.py:2422: pyo3_runtime.PanicException
Local polars 1.42 handles the same expression fine, so this is invisible outside the RAPIDS
image — 10 test failures on the GPU box, 0 locally, on identical code.
Why it is a hazard beyond one polars version
pyo3_runtime.PanicException is not a polars.exceptions.PolarsError. #1819 added a choke point
in the native polars chain that rewraps polars errors as GFQLTypeError(E303) so a third-party class
never reaches the caller — and that wrapper cannot catch this. A Rust panic escaping through the
GFQL surface is uncatchable by construction on the python side, so the only defence is not to emit
the expression that panics.
Workaround already in place (#1819)
Categorical/Enum columns are cast to String before any aggregate on both engines — which is
independently correct (Cypher treats a categorical as a string column, and it also fixed pandas
raising and cuDF answering count(DISTINCT <categorical>) with a category label). Pinned by a test
that asserts the result dtype is String, because the failure it prevents is version-dependent
and a value assertion on polars 1.42 cannot see it:
graphistry/tests/compute/gfql/test_aggregate_type_contract.py::test_categorical_is_decategorized_before_aggregating_on_polars
What is left to decide
- Whether other polars expressions this repo emits can panic the same way on the pinned image
version — a survey, not a guess. Anything Categorical-typed reaching a polars kernel is suspect.
- Whether the polars version drift between the RAPIDS image (1.35.2) and local dev (1.42) should be
closed or at least asserted, since it silently changes which defects are observable. Related
standing note: validate in-container before measuring anything polars-version-sensitive.
Surfaced by the GPU lane of #1819 on the dgx GB10
(
graphistry/test-rapids-official:26.02-gfql-polars, polars 1.35.2). Worked around there, butthe underlying hazard is general and worth its own record.
What happens
A grouped
min()/max()over a Categorical column makes polars 1.35.2 panic in its Rust core:Local polars 1.42 handles the same expression fine, so this is invisible outside the RAPIDS
image — 10 test failures on the GPU box, 0 locally, on identical code.
Why it is a hazard beyond one polars version
pyo3_runtime.PanicExceptionis not apolars.exceptions.PolarsError. #1819 added a choke pointin the native polars chain that rewraps polars errors as
GFQLTypeError(E303)so a third-party classnever reaches the caller — and that wrapper cannot catch this. A Rust panic escaping through the
GFQL surface is uncatchable by construction on the python side, so the only defence is not to emit
the expression that panics.
Workaround already in place (#1819)
Categorical/Enum columns are cast to
Stringbefore any aggregate on both engines — which isindependently correct (Cypher treats a categorical as a string column, and it also fixed pandas
raising and cuDF answering
count(DISTINCT <categorical>)with a category label). Pinned by a testthat asserts the result dtype is
String, because the failure it prevents is version-dependentand a value assertion on polars 1.42 cannot see it:
graphistry/tests/compute/gfql/test_aggregate_type_contract.py::test_categorical_is_decategorized_before_aggregating_on_polarsWhat is left to decide
version — a survey, not a guess. Anything Categorical-typed reaching a polars kernel is suspect.
closed or at least asserted, since it silently changes which defects are observable. Related
standing note: validate in-container before measuring anything polars-version-sensitive.