{"record":{"id":"b25b49353a2838df","repo":"risingwavelabs/risingwave","slug":"incompatible-requirements-a-and-b","errorCode":null,"errorMessage":"incompatible requirements `{a:?}` and `{b:?}`","messagePattern":"incompatible requirements `(.+?)` and `(.+?)`","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/stream/stream_graph/schedule.rs","lineNumber":70,"sourceCode":"    #[expect(non_upper_case_globals)]\n    const AnySingleton: Self = Self::AnyVnodeCount(1);\n\n    /// Merge two requirements. Returns an error if the requirements are incompatible.\n    ///\n    /// The `mapping_len` function is used to get the vnode count of a hash mapping by its id.\n    fn merge(a: Self, b: Self, mapping_len: impl Fn(HashMappingId) -> usize) -> MetaResult<Self> {\n        // Note that a and b are always different, as they come from a set.\n        let merge = |a, b| match (a, b) {\n            (Self::AnySingleton, Self::Singleton) => Some(Self::Singleton),\n            (Self::AnyVnodeCount(count), Self::Hash(id)) if mapping_len(id) == count => {\n                Some(Self::Hash(id))\n            }\n            _ => None,\n        };\n\n        match merge(a, b).or_else(|| merge(b, a)) {\n            Some(req) => Ok(req),\n            None => bail!(\"incompatible requirements `{a:?}` and `{b:?}`\"),\n        }\n    }\n}\n\n/// Facts as the input of the scheduler.\n#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]\nenum Fact {\n    /// An edge in the fragment graph.\n    Edge {\n        from: Id,\n        to: Id,\n        dt: DispatcherType,\n    },\n    /// A scheduling requirement for a fragment.\n    Req { id: Id, req: Req },\n}\n\ncrepe::crepe! {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/stream/stream_graph/schedule.rs#L52-L88","documentation":"The distributed scheduling scheduler merges requirement facts (e.g. distribution/consistency requirements) from both sides of an edge. `Requirements::merge` must yield a result for `a` merged into `b` or `b` merged into `a`; if neither succeeds, the two requirement sets conflict and the builder bails. This means two fragments demand mutually exclusive scheduling properties.","triggerScenarios":"Building a stream graph where an upstream and downstream fragment (or a fragment and job-level requirement) carry incompatible requirement values — e.g. one requires single/different distribution or conflicting hash/consistency settings — so `merge(a, b)` and `merge(b, a)` both return None.","commonSituations":"Combining operators/nodes with conflicting scheduling hints (e.g. joining a globally distributed MV with a single-fragment requirement), custom/modified stream nodes with mismatched requirement declarations, planner bugs attaching wrong requirements to edges.","solutions":["Check which two requirement values conflict from the `{a:?}`/`{b:?}` in the message and adjust the SQL or node that forces the stricter requirement.","If a custom operator declares requirements, make its merge impl accept the counterpart or align the declarations.","File a bug with the DDL if two ordinary MVs/operators conflict; rewrite the query to avoid the conflicting construct."],"exampleFix":"// before\nmatch merge(a, b).or_else(|| merge(b, a)) { Some(req) => Ok(req), None => bail!(...) }\n// after: relax a conflicting requirement explicitly in merge\nfn merge(a: &Requirements, b: &Requirements) -> Option<Requirements> {\n    // handle previously incompatible combo, e.g. prefer the stricter side\n    ...\n}","handlingStrategy":"validation","validationCode":"// Pre-check that edge requirements can merge before scheduling\nlet merged = req_a.merge(&req_b).or_else(|| req_b.merge(&req_a));\nif merged.is_none() {\n    return Err(format!(\"requirements {:?} and {:?} conflict\", req_a, req_b));\n}","typeGuard":null,"tryCatchPattern":"match build_graph() {\n    Err(e) if e.to_string().starts_with(\"incompatible requirements\") => {\n        // relax/adjust the conflicting requirement and retry\n    }\n    other => other?,\n}","preventionTips":["Avoid mixing operators/objects with conflicting distribution or consistency requirements","Keep requirement merge implementations complete for all declared combos","Add tests that merge every pair of requirement variants"],"tags":["meta","scheduler","requirements"],"backgroundTag":"conflicting-config-options","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"}