risingwavelabs/risingwave · error · StreamExecutorError
right barrier received while left stream end
Error message
right barrier received while left stream end
What it means
In `barrier_align`, after the right input stream ended, the left stream delivered a Barrier. Barrier alignment requires both inputs to see barriers in lockstep; a barrier on a stream whose counterpart already ended breaks the alignment protocol, so it aborts.
Source
Thrown at src/stream/src/executor/barrier_align.rs:87
let select_result = if prefer_left {
select(left.next(), right.next()).await
} else {
match select(right.next(), left.next()).await {
Either::Left(x) => Either::Right(x),
Either::Right(x) => Either::Left(x),
}
};
match select_result {
Either::Left((None, _)) => {
// left stream end, passthrough right chunks
while let Some(msg) = right.next().await {
match msg? {
Message::Watermark(watermark) => {
yield AlignedMessage::WatermarkRight(watermark)
}
Message::Chunk(chunk) => yield AlignedMessage::Right(chunk),
Message::Barrier(_) => {
bail!("right barrier received while left stream end");
}
}
}
break;
}
Either::Right((None, _)) => {
// right stream end, passthrough left chunks
while let Some(msg) = left.next().await {
match msg? {
Message::Watermark(watermark) => {
yield AlignedMessage::WatermarkLeft(watermark)
}
Message::Chunk(chunk) => yield AlignedMessage::Left(chunk),
Message::Barrier(_) => {
bail!("left barrier received while right stream end");
}
}
}View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure both upstreams feeding the aligned executor have the same lifetime and are torn down together.
- Check for upstream failures that closed one side prematurely (look for earlier errors on that actor).
- Fix test/executor wiring so barrier streams are not terminated independently.
Defensive patterns
Strategy: validation
Validate before calling
// ensure upstreams share lifetime: end both streams at the same barrier assert_eq!(left.barrier_count(), right.barrier_count());
Try / catch
match barrier_align(left, right).next().await { Some(Err(e)) if e.to_string().contains("received while") => { tear_down_both(); } other => ... } Prevention
- Wire binary-operator upstreams so they are dropped together
- Fail both sides when either upstream fails
- Keep test streams symmetric with matching barriers
When it happens
Trigger: Two-input alignment where one input finishes while the other still emits barriers — e.g. mismatched upstream lifetimes feeding a binary executor, or a test harness (`barrier_align_for_test`) with asymmetric stream ends.
Common situations: Binary operators (join/union) whose upstreams terminate at different times; network failure ending one upstream early; incorrectly constructed test streams.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- left barrier received while right stream end
- Exchange executor should not have children!
- Iceberg source should not have input executor!
- core predicate must exist
- batch refresh job {} has no snapshot backfill info
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/0ac3a4a5dde892e1.
Report an issue: GitHub.