{"record":{"id":"f711f1a53eb0b06a","repo":"pola-rs/polars","slug":"merge-join-kernel-not-implemented-for","errorCode":null,"errorMessage":"merge-join kernel not implemented for {:?}","messagePattern":"merge-join kernel not implemented for (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/polars-ops/src/frame/join/merge_join.rs","lineNumber":84,"sourceCode":"            type PhysCa = ChunkedArray<<$C as PolarsCategoricalType>::PolarsPhysical>;\n            let build_keys_ca: &PhysCa = build_keys.as_ref().as_ref();\n            dispatch!(build_keys_ca)\n        }),\n        DataType::Null => match_null_keys_impl(\n            build_keys.len(),\n            probe_keys.len(),\n            gather_build,\n            gather_probe,\n            gather_probe_unmatched,\n            build_emit_unmatched,\n            descending,\n            nulls_equal,\n            limit_results,\n            build_row_offset,\n            probe_row_offset,\n            probe_last_matched,\n        ),\n        dt => unimplemented!(\"merge-join kernel not implemented for {:?}\", dt),\n    }\n}\n\n#[allow(clippy::mut_range_bound, clippy::too_many_arguments)]\nfn match_keys_impl<'a, T: PolarsDataType>(\n    build_keys: &'a ChunkedArray<T>,\n    probe_keys: &'a ChunkedArray<T>,\n    gather_build: &mut Vec<IdxSize>,\n    gather_probe: &mut Vec<IdxSize>,\n    mut gather_probe_unmatched: Option<&mut Vec<IdxSize>>,\n    build_emit_unmatched: bool,\n    descending: bool,\n    nulls_equal: bool,\n    limit_results: usize,\n    build_row_offset: &mut usize,\n    probe_row_offset: &mut usize,\n    probe_first_unmatched: &mut usize,\n) where","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/pola-rs/polars/blob/df599052daf96e7a9cc30a3b0c6bd25d6947e3c0/crates/polars-ops/src/frame/join/merge_join.rs#L66-L102","documentation":"The streaming-engine merge-join kernel (used for sorted equi-joins / IEJoin-style plans) only implements key dtypes that are primitive numeric, Boolean, String, Binary, BinaryOffset, Enum, or Null. Any other key dtype - notably Categorical (unlike Enum), temporal dtypes not pre-cast to physical, and other nested/exotic types - hits the unimplemented!() fallback.","triggerScenarios":"Running a join under the streaming engine (engine='streaming', or default in recent versions) whose join keys have an unsupported dtype, e.g. joining on a Categorical key column that has not been unified to Enum/String/physical representation.","commonSituations":"Joins on string-cache categoricals or on keys whose dtype changed after concat/concat_relaxed; queries that only panic once the planner picks the merge-join path (sorted inputs, ordered joins).","solutions":["Cast join keys to a supported dtype before the join: .cast(pl.String) for categoricals, or to Int64 physical for temporals if needed","Convert categorical keys to a shared Enum or String dtype on both sides before joining","Run the query with the in-memory engine (engine='in-memory') as a workaround while keys are non-standard"],"exampleFix":"# before\nout = df1.join(df2, on=\"cat_key\")  # categorical keys + streaming merge-join -> panic\n\n# after\nout = df1.with_columns(pl.col(\"cat_key\").cast(pl.String)).join(\n    df2.with_columns(pl.col(\"cat_key\").cast(pl.String)), on=\"cat_key\"\n)","handlingStrategy":"validation","validationCode":"MERGE_JOIN_KEYS = (\n    set(pl.INTEGER_DTYPES) | set(pl.FLOAT_DTYPES)\n    | {pl.Boolean, pl.String, pl.Binary, pl.Null}\n)\ndef merge_join_keys_ok(*keys: pl.Series) -> bool:\n    return all(k.dtype in MERGE_JOIN_KEYS or isinstance(k.dtype, pl.Enum) for k in keys)","typeGuard":"def merge_join_key(s: pl.Series) -> pl.Series:\n    if not (s.dtype.is_numeric() or s.dtype in (pl.Boolean, pl.String, pl.Binary, pl.Null)) \\\n       and not isinstance(s.dtype, pl.Enum):\n        return s.cast(pl.String)\n    return s","tryCatchPattern":null,"preventionTips":["Cast categorical join keys to String or a shared Enum before joining under the streaming engine","Watch for dtype drift (String vs Categorical) after concat; align keys explicitly"],"tags":["rust","polars","panic","unimplemented","join","merge-join","streaming","dtype"],"backgroundTag":null,"analyzedSha":"df599052daf96e7a9cc30a3b0c6bd25d6947e3c0","analyzedAt":"2026-08-16T12:10:03.978Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}