{"record":{"id":"189106cbb14e5204","repo":"risingwavelabs/risingwave","slug":"failed-to-match-operator-from-to-to-message","errorCode":null,"errorMessage":"failed to match operator {from} to {to}: {message}","messagePattern":"failed to match operator (.+?) to (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/stream_graph/state_match.rs","lineNumber":66,"sourceCode":"    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(f, \"{}\", self.0)\n    }\n}\n\n/// Error type for failed state table matching.\n#[derive(thiserror::Error, thiserror_ext::Macro, thiserror_ext::ReportDebug)]\npub(crate) enum Error {\n    #[error(\"failed to match graph: {message}\")]\n    Graph { message: String },\n\n    #[error(\"failed to match fragment {id}: {message}\")]\n    Fragment {\n        source: Option<Box<Error>>,\n        id: Id,\n        message: String,\n    },\n\n    #[error(\"failed to match operator {from} to {to}: {message}\")]\n    Operator {\n        from: StreamNodeDesc,\n        to: StreamNodeDesc,\n        message: String,\n    },\n}\n\ntype Result<T, E = Error> = std::result::Result<T, E>;\n\n/// Fragment id.\ntype Id = FragmentId;\n\n/// Node for a fragment in the [`Graph`].\nstruct Fragment {\n    /// The fragment id.\n    id: Id,\n    /// The root node of the fragment.\n    root: StreamNode,","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/stream_graph/state_match.rs#L48-L84","documentation":"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.).","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"null","typeGuard":"if let state_match::Error::Operator { from, to, message } = &err {\n    eprintln!(\"operator {} -> {} mismatch: {}\", from, to, message);\n}","tryCatchPattern":"match state_match::match_graph(&old, &new) {\n    Err(state_match::Error::Operator { from, to, message }) => {\n        tracing::warn!(\"operator change not supported ({} vs {}): {}; recreate the job\", from, to, message);\n    }\n    Err(e) => return Err(e.into()),\n    Ok(tables) => apply(tables),\n}","preventionTips":["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"],"tags":["meta","schema-change","operators"],"backgroundTag":"schema-validation-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}