risingwavelabs/risingwave · error · Error
failed to match operator
Error message
failed to match operator {from} to {to}: {message} What it means
A `state_match::Error::Operator` variant raised when an operator node `from` in the old graph cannot be matched to operator `to` in the new graph during schema-change state table matching. `from`/`to` are `StreamNodeDesc` descriptions, and `message` explains why they mismatch (different node type, changed fields, etc.).
Solutions
- Read `{from}` vs `{to}` in the message to identify the diverging operator; restrict the ALTER so that operator stays semantically identical.
- Recreate the MV/table with the desired definition if the change is inherently incompatible with in-place schema change.
- Upgrade both nodes to matching versions if the mismatch stems from operator representation changes between releases.
Defensive patterns
Strategy: try-catch
Validate before calling
null
Type guard
if let state_match::Error::Operator { from, to, message } = &err {
eprintln!("operator {} -> {} mismatch: {}", from, to, message);
} Try / catch
match state_match::match_graph(&old, &new) {
Err(state_match::Error::Operator { from, to, message }) => {
tracing::warn!("operator change not supported ({} vs {}): {}; recreate the job", from, to, message);
}
Err(e) => return Err(e.into()),
Ok(tables) => apply(tables),
} Prevention
- Keep expressions feeding materialized operators stable across ALTERs
- Compare old/new explain plans before running schema changes on important MVs
- Upgrade all nodes together to avoid operator-encoding drift
When it happens
Trigger: Matching graphs where corresponding operators differ — node type changed, node fields (e.g. projection, predicate, aggregator definitions) changed beyond what matching allows — producing this operator-level error, often nested inside Fragment/Graph errors.
Common situations: ALTER statements that change expressions/transforms feeding materialized operators, or version upgrades that alter operator encodings so old and new nodes no longer compare equal.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- failed to match fragment
- failed to match graph
- sink with auto schema change should have only 1 fragment…
- unsupported job type for replacement
- id not found
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/189106cbb14e5204.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/src/stream/stream_graph/state_match.rs:66
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
/// Error type for failed state table matching.
#[derive(thiserror::Error, thiserror_ext::Macro, thiserror_ext::ReportDebug)]
pub(crate) enum Error {
#[error("failed to match graph: {message}")]
Graph { message: String },
#[error("failed to match fragment {id}: {message}")]
Fragment {
source: Option<Box<Error>>,
id: Id,
message: String,
},
#[error("failed to match operator {from} to {to}: {message}")]
Operator {
from: StreamNodeDesc,
to: StreamNodeDesc,
message: String,
},
}
type Result<T, E = Error> = std::result::Result<T, E>;
/// Fragment id.
type Id = FragmentId;
/// Node for a fragment in the [`Graph`].
struct Fragment {
/// The fragment id.
id: Id,
/// The root node of the fragment.
root: StreamNode,View on GitHub (pinned to 6469eb736d)