risingwavelabs/risingwave · error
expected but got
Error message
expected {} but got {:?} What it means
A macro-generated TryFrom<SplitImpl> conversion failed: the SplitImpl enum held a different connector's split variant than the one being downcast to. risingwave_common::bail! produces 'expected <Variant> but got <actual>'. Note the eq/partial_cmp uses shown at top_n.rs are unrelated PartialEq impls; the error itself originates in the macro's try_from.
Solutions
- Check the WITH connector type of the source/table matches the expected split type
- Recreate the sink/source or restart the query so splits are regenerated for the correct connector
- If seen after a version upgrade, clear stale split state (recovery/recreate) and report the mismatch
Example fix
// before
let s: KafkaSplit = split.try_into()?; // split is actually an IcebergSplit
// after
let SplitImpl::Kafka(s) = &split else { return Err(anyhow!("unexpected split {:?}", split)); }; Defensive patterns
Strategy: type-guard
Validate before calling
fn expect_kafka_split(split: &SplitImpl) -> Option<&KafkaSplit> {
match split { SplitImpl::Kafka(s) => Some(s), _ => None }
} Type guard
fn as_variant<T: 'static>(split: &SplitImpl, f: impl Fn(&SplitImpl) -> Option<&T>) -> Option<&T> { f(split) }
// or simply:
fn is_kafka(split: &SplitImpl) -> bool { matches!(split, SplitImpl::Kafka(_)) } Try / catch
let kafka_split: KafkaSplit = SplitImpl::try_from(split.clone())
.map_err(|e| anyhow!("split routing mismatch: {}", e))?; Prevention
- Ensure each executor/scan only receives splits generated by its own connector
- Avoid reusing persisted split metadata across connector type changes
- Add assertions on split type at fragment assignment time
When it happens
Trigger: Casting a SplitImpl to a concrete split type (e.g. SplitImpl::try_into::<KafkaSplit>()) when the split actually belongs to another connector, typically due to mixed-up sources, a scheduler bug, or misconfigured fragment/split assignment.
Common situations: Batch execution or recovery after a catalog change where splits persisted for one connector are replayed against another; running queries over a source whose connector type changed; internal split-routing bugs.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- {0}
- additional column is not supported for connector
- additional column type
- argument type mismatch, expect
- Array error
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/3d682e594dda5355.
Report an issue: GitHub.
Appendix: source
Thrown at src/connector/src/macros.rs:307
#[macro_export]
macro_rules! impl_split {
({$({ $variant_name:ident, $prop_name:ty, $split:ty}),*}) => {
#[derive(Debug, Clone, EnumAsInner, PartialEq)]
pub enum SplitImpl {
$(
$variant_name($split),
)*
}
$(
impl TryFrom<SplitImpl> for $split {
type Error = $crate::error::ConnectorError;
fn try_from(split: SplitImpl) -> std::result::Result<Self, Self::Error> {
match split {
SplitImpl::$variant_name(inner) => Ok(inner),
other => risingwave_common::bail!(
"expected {} but got {:?}",
stringify!($split),
other
),
}
}
}
impl From<$split> for SplitImpl {
fn from(split: $split) -> SplitImpl {
SplitImpl::$variant_name(split)
}
}
)*
}
}
View on GitHub (pinned to 6469eb736d)