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
- 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.
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
- 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
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
- Pin snapshot error: fails to get epoch
- {0}
- id not found
- named already exists
- actor count ( ) exceeds vnode count ( )
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)