pola-rs/polars · error
merge-join kernel not implemented for {:?}
Error message
merge-join kernel not implemented for {:?} What it means
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.
Source
Thrown at crates/polars-ops/src/frame/join/merge_join.rs:84
type PhysCa = ChunkedArray<<$C as PolarsCategoricalType>::PolarsPhysical>;
let build_keys_ca: &PhysCa = build_keys.as_ref().as_ref();
dispatch!(build_keys_ca)
}),
DataType::Null => match_null_keys_impl(
build_keys.len(),
probe_keys.len(),
gather_build,
gather_probe,
gather_probe_unmatched,
build_emit_unmatched,
descending,
nulls_equal,
limit_results,
build_row_offset,
probe_row_offset,
probe_last_matched,
),
dt => unimplemented!("merge-join kernel not implemented for {:?}", dt),
}
}
#[allow(clippy::mut_range_bound, clippy::too_many_arguments)]
fn match_keys_impl<'a, T: PolarsDataType>(
build_keys: &'a ChunkedArray<T>,
probe_keys: &'a ChunkedArray<T>,
gather_build: &mut Vec<IdxSize>,
gather_probe: &mut Vec<IdxSize>,
mut gather_probe_unmatched: Option<&mut Vec<IdxSize>>,
build_emit_unmatched: bool,
descending: bool,
nulls_equal: bool,
limit_results: usize,
build_row_offset: &mut usize,
probe_row_offset: &mut usize,
probe_first_unmatched: &mut usize,
) whereView on GitHub (pinned to df599052da)
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
Example fix
# before
out = df1.join(df2, on="cat_key") # categorical keys + streaming merge-join -> panic
# after
out = df1.with_columns(pl.col("cat_key").cast(pl.String)).join(
df2.with_columns(pl.col("cat_key").cast(pl.String)), on="cat_key"
) Defensive patterns
Strategy: validation
Validate before calling
MERGE_JOIN_KEYS = (
set(pl.INTEGER_DTYPES) | set(pl.FLOAT_DTYPES)
| {pl.Boolean, pl.String, pl.Binary, pl.Null}
)
def merge_join_keys_ok(*keys: pl.Series) -> bool:
return all(k.dtype in MERGE_JOIN_KEYS or isinstance(k.dtype, pl.Enum) for k in keys) Type guard
def merge_join_key(s: pl.Series) -> pl.Series:
if not (s.dtype.is_numeric() or s.dtype in (pl.Boolean, pl.String, pl.Binary, pl.Null)) \
and not isinstance(s.dtype, pl.Enum):
return s.cast(pl.String)
return s Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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).
Related errors
- not implemented
- not implemented
- horizontal_flatten not supported for data type {:?}
- can not get dtype of Categorical AnyValue
- can not get dtype of Enum AnyValue
AI-assisted analysis of pola-rs/polars@df599052da (2026-08-16).
Data as JSON: /api/errors/f711f1a53eb0b06a.
Report an issue: GitHub.