{"record":{"id":"a4a563439ccc31ef","repo":"pola-rs/polars","slug":"cross-join-filter-holds-no-keys","errorCode":null,"errorMessage":"cross join filter holds no keys","messagePattern":"cross join filter holds no keys","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/polars-plan/src/plans/options.rs","lineNumber":739,"sourceCode":"    /// On [`Self::CrossAndFilter`], which holds no keys, or on a length mismatch where the\n    /// variant stores keys in pairs.\n    pub fn set_keys(&mut self, left: Vec<ExprIR>, right: Vec<ExprIR>) {\n        if let Some(on) = self.key_pairs_mut() {\n            *on = left.into_iter().zip_eq(right).collect();\n            return;\n        }\n        match self {\n            #[cfg(feature = \"iejoin\")]\n            Self::IEJoin {\n                left_on, right_on, ..\n            }\n            | Self::Range {\n                left_on, right_on, ..\n            } => {\n                *left_on = left;\n                *right_on = right;\n            },\n            _ => panic!(\"cross join filter holds no keys\"),\n        }\n    }\n\n    /// The match condition is exactly `left == right` for every key pair.\n    ///\n    /// True for [`Self::AsOf`] too: its strategy and tolerance live in [`JoinType::AsOf`],\n    /// not in the match condition. False once a fused predicate is attached.\n    pub fn is_pure_equi(&self) -> bool {\n        !self.is_non_equi()\n    }\n\n    /// The match condition has a non-equality component.\n    ///\n    /// Use [`Self::key_pairs`] instead where what is needed is paired keys: a fused predicate\n    /// join has those as well.\n    pub fn is_non_equi(&self) -> bool {\n        self.key_pairs().is_none() || self.has_fused_predicate()\n    }","sourceCodeStart":721,"sourceCodeEnd":757,"githubUrl":"https://github.com/pola-rs/polars/blob/68506541d2de983056c9eb244e1ea05fab377dfc/crates/polars-plan/src/plans/options.rs#L721-L757","documentation":"Internal Rust panic in polars-plan indicating that a cross join's filter was expected to hold join keys but the JoinType variant being mutated has no key slots. It fires when code calls the key-setting helper on a join type other than the variants that store left_on/right_on keys (e.g. Range). This is an invariant violation inside the query planner, not a user-input error.","triggerScenarios":"Calling the internal key-assignment API (the method containing 'Self::Range { left_on, right_on, .. }' in crates/polars-plan/src/plans/options.rs:663) on a JoinType variant such as a cross join that carries no key columns; typically reached via programmatic construction or optimization passes that reassign join keys.","commonSituations":"Contributors modifying join planning code, adding a new JoinType variant, or optimizations that rewrite join keys on already-built join nodes. End users essentially never see this unless a higher-level API misroutes a join configuration into the planner.","solutions":["If you are a polars contributor: handle the new/remaining JoinType variants explicitly instead of the wildcard _ arm","Verify the JoinType is one that holds keys (Range/I Equi variants) before calling the setter","If hit from Python, minimize the reproducing query and report it as a polars bug with the query plan","Check you are on the latest polars release; planner panics are often fixed quickly"],"exampleFix":"// before\n(join_type, keys) = match join_type { _ => panic!(\"cross join filter holds no keys\") }\n// after\nmatch join_type {\n    Self::Range { left_on, right_on, .. } => { *left_on = left; *right_on = right; },\n    other => return Err(PolarsError::InvalidOperation(\"join type holds no keys\".into())),\n}","handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin a stable polars release in production","Add regression tests covering join configurations you rely on","Report planner panics upstream with a minimal reproducer"],"tags":["rust","polars","join","panic","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"68506541d2de983056c9eb244e1ea05fab377dfc","analyzedAt":"2026-08-28T18:02:35.179Z","contentChangedAt":"2026-08-28T18:02:35.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}