{"record":{"id":"59ba477912b3e076","repo":"pola-rs/polars","slug":"expected-total-ordering","errorCode":null,"errorMessage":"expected total ordering","messagePattern":"expected total ordering","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-utils/src/sort.rs","lineNumber":119,"sourceCode":"{\n    fn cmp(&self, other: &Self) -> Ordering {\n        reorder_cmp(&self.0, &other.0, DESCENDING, NULLS_LAST)\n    }\n}\n\n/// Compare two values with support for sort direction and nulls position.\n///\n/// # Panics\n///\n/// Panics if `T::partial_cmp(lhs, rhs)` returns `None`.\n#[inline]\npub fn reorder_cmp<T: PartialOrd + IsNull>(\n    lhs: &T,\n    rhs: &T,\n    descending: bool,\n    nulls_last: bool,\n) -> Ordering {\n    match PartialOrd::partial_cmp(lhs, rhs).expect(\"expected total ordering\") {\n        Ordering::Equal => Ordering::Equal,\n        _ if lhs.is_null() && nulls_last => Ordering::Greater,\n        _ if rhs.is_null() && nulls_last => Ordering::Less,\n        _ if lhs.is_null() => Ordering::Less,\n        _ if rhs.is_null() => Ordering::Greater,\n        ord if descending => ord.reverse(),\n        ord => ord,\n    }\n}\n","sourceCodeStart":101,"sourceCodeEnd":129,"githubUrl":"https://github.com/pola-rs/polars/blob/fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e/crates/polars-utils/src/sort.rs#L101-L129","documentation":"reorder_cmp uses PartialOrd::partial_cmp and unwraps with 'expected total ordering'; if partial_cmp returns None the type's comparison is not a total order (e.g. NaN floats) and it panics. Null handling is done after, so the panic fires for non-null values that cannot be ordered.","triggerScenarios":"Sorting/ordering columns containing NaN or other values where partial_cmp yields None; calling arg_sort_multiple or any of its helpers (cmp_element_unchecked, cmp_at, etc.) on such data.","commonSituations":"Sorting float columns with NaN; user-defined or exotic types with inconsistent Ord; comparing mixed-type or corrupted data in multi-column sorts.","solutions":["Sanitize data before sorting: replace NaN with null (fill_nan) or a sentinel so null handling takes over","Use sort options that treat NaN explicitly, or drop/fillna NaN values first","Verify custom element types implement a true total order (Ord, not just PartialOrd)"],"exampleFix":"// before\ndf.sort([\"price\"], SortMultipleOptions::default());\n// after\nlet df = df.with_column(col(\"price\").fill_nan(lit(f64::NAN).is_null())).unwrap(); // or fill_nan(lit(0.0))\ndf.sort([\"price\"], SortMultipleOptions::default());","handlingStrategy":"validation","validationCode":"# Polars: remove non-orderable NaN before sorting\ns = df[\"price\"]\nassert not s.drop_nulls().is_nan().any(), \"NaN values break total ordering; use fill_nan or drop them\"","typeGuard":null,"tryCatchPattern":null,"preventionTips":["fill_nan or drop NaN values before arg_sort/sort operations","For custom element types, implement Ord (total order), not just PartialOrd","Test multi-column sorts on data containing NaN and nulls"],"tags":["rust","sorting","partialord","nan","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"fe841f959ef4d2ceefc05a310d33ed7b1ab24e5e","analyzedAt":"2026-09-18T22:14:11.667Z","contentChangedAt":"2026-09-18T22:14:11.667Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}