risingwavelabs/risingwave · error · StreamExecutorError
Channel closed: {0}
Error message
Channel closed: {0} What it means
The ChannelClosed variant carries a human-readable message ('Channel closed: {0}') describing a closed internal channel inside the streaming executor. It indicates the executor tried to send or receive over a channel whose other end has been dropped, usually because a downstream/upstream actor has terminated.
Source
Thrown at src/stream/src/executor/error.rs:85
BoxedError,
),
#[error("Sink error: sink_id={1}, error: {0}")]
SinkError(
#[source]
#[backtrace]
SinkError,
SinkId,
),
#[error(transparent)]
RpcError(
#[from]
#[backtrace]
RpcError,
),
#[error("Channel closed: {0}")]
ChannelClosed(String),
#[error(transparent)]
ExchangeChannelClosed(
#[from]
#[backtrace]
ExchangeChannelClosed,
),
#[error("Failed to align barrier: expected `{0:?}` but got `{1:?}`")]
AlignBarrier(Box<Barrier>, Box<Barrier>),
#[error("Connector error: {0}")]
ConnectorError(
#[source]
#[backtrace]
BoxedError,
),View on GitHub (pinned to 6469eb736d)
Solutions
- Look at sibling actor logs to find why the peer actor terminated first (the root failure is usually upstream).
- Check for panics or OOM kills in the compute node logs.
- Rely on actor restart/failover to rebuild channels; investigate repeated closures for deterministic failures.
- Ensure barrier alignment and termination logic closes channels gracefully rather than dropping them.
Defensive patterns
Strategy: try-catch
Validate before calling
// before sending, check channel liveness
if sender.is_closed() {
tracing::warn!("downstream channel already closed; skipping send");
return Ok(());
} Type guard
fn is_channel_closed(e: &StreamExecutorError) -> bool {
e.variant_name() == "ChannelClosed"
} Try / catch
if let Err(e) = res {
if e.variant_name() == "ChannelClosed" {
// peer actor gone; let failover rebuild the graph
return Ok(());
}
return Err(e.into());
} Prevention
- Ensure actors terminate via barrier-driven graceful stop, not abrupt drops.
- Check peer actor health before long-lived sends.
- Watch compute node logs for panics/OOM that kill peers.
- Handle shutdown ordering so receivers outlive senders.
When it happens
Trigger: Created via ErrorKind::ChannelClosed(format!(...)) at points where the executor finds its exchange channel handle closed; e.g. sending barriers or chunks after the remote actor exited.
Common situations: A downstream actor panicked or failed and its channel receiver was dropped; actor rescale/kill during runtime; shutdown races where data is still in flight.
Related errors
- ExchangeChannelClosed
- failed to send the rebuild-sink request to the reader
- failed to receive rebuild sink notify
- broken broadcast_channel
- broken hash_shuffle_channel
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/62a5cbc78660d0db.
Report an issue: GitHub.