risingwavelabs/risingwave · error

incompatible requirements

Error message

incompatible requirements `{a:?}` and `{b:?}`

What it means

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.

Solutions

  1. Check which two requirement values conflict from the `{a:?}`/`{b:?}` in the message and adjust the SQL or node that forces the stricter requirement.
  2. If a custom operator declares requirements, make its merge impl accept the counterpart or align the declarations.
  3. File a bug with the DDL if two ordinary MVs/operators conflict; rewrite the query to avoid the conflicting construct.

Example fix

// before
match merge(a, b).or_else(|| merge(b, a)) { Some(req) => Ok(req), None => bail!(...) }
// after: relax a conflicting requirement explicitly in merge
fn merge(a: &Requirements, b: &Requirements) -> Option<Requirements> {
    // handle previously incompatible combo, e.g. prefer the stricter side
    ...
}
Defensive patterns

Strategy: validation

Validate before calling

// Pre-check that edge requirements can merge before scheduling
let merged = req_a.merge(&req_b).or_else(|| req_b.merge(&req_a));
if merged.is_none() {
    return Err(format!("requirements {:?} and {:?} conflict", req_a, req_b));
}

Try / catch

match build_graph() {
    Err(e) if e.to_string().starts_with("incompatible requirements") => {
        // relax/adjust the conflicting requirement and retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/b25b49353a2838df. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/src/stream/stream_graph/schedule.rs:70

    #[expect(non_upper_case_globals)]
    const AnySingleton: Self = Self::AnyVnodeCount(1);

    /// Merge two requirements. Returns an error if the requirements are incompatible.
    ///
    /// The `mapping_len` function is used to get the vnode count of a hash mapping by its id.
    fn merge(a: Self, b: Self, mapping_len: impl Fn(HashMappingId) -> usize) -> MetaResult<Self> {
        // Note that a and b are always different, as they come from a set.
        let merge = |a, b| match (a, b) {
            (Self::AnySingleton, Self::Singleton) => Some(Self::Singleton),
            (Self::AnyVnodeCount(count), Self::Hash(id)) if mapping_len(id) == count => {
                Some(Self::Hash(id))
            }
            _ => None,
        };

        match merge(a, b).or_else(|| merge(b, a)) {
            Some(req) => Ok(req),
            None => bail!("incompatible requirements `{a:?}` and `{b:?}`"),
        }
    }
}

/// Facts as the input of the scheduler.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Fact {
    /// An edge in the fragment graph.
    Edge {
        from: Id,
        to: Id,
        dt: DispatcherType,
    },
    /// A scheduling requirement for a fragment.
    Req { id: Id, req: Req },
}

crepe::crepe! {

View on GitHub (pinned to 6469eb736d)