risingwavelabs/risingwave · error

rhs buffer should not be empty

Error message

rhs buffer should not be empty 

What it means

Identical invariant to the lhs check in `flush_buffers`: the row-merge executor requires at least one buffered chunk on the right (rhs) side before it can pair chunks. Draining an empty rhs buffer means the right input never staged data for the epoch being flushed.

Solutions

  1. Log rhs buffer contents per epoch and file an issue — internal invariant violation, not caused by user SQL
  2. Recreate the streaming job to reset buffer state as a workaround
  3. Check upstream right-side actor health (no chunks at all may indicate a dead/inactive producer)
  4. Upgrade to a RisingWave version with row_merge buffering fixes
Defensive patterns

Strategy: try-catch

Try / catch

match merge_result {
    Err(e) if e.to_string().contains("rhs buffer should not be empty") => {
        // Right input never staged chunks for this epoch: recreate the job after checking upstream health
        verify_right_upstream_actor_health();
        recreate_streaming_job(job_id);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Internal: `flush_buffers` called when the rhs buffer was never populated for the current epoch — right input barrier arrived without preceding chunks, or epoch bookkeeping desynced between sides.

Common situations: Uneven chunk arrival on the two inputs of a row-merge pipeline; upstream right-side actor producing only barriers; version regressions in epoch buffering.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/stream/src/executor/row_merge.rs:126

                    }
                }
            }
        }
    }

    #[try_stream(ok = Message, error = StreamExecutorError)]
    async fn flush_buffers<'a>(
        data_types: &'a [DataType],
        lhs_mapping: &'a ColIndexMapping,
        rhs_mapping: &'a ColIndexMapping,
        lhs_buffer: &'a mut Vec<StreamChunk>,
        rhs_buffer: &'a mut Vec<StreamChunk>,
    ) {
        if lhs_buffer.is_empty() {
            bail!("lhs buffer should not be empty ");
        };
        if rhs_buffer.is_empty() {
            bail!("rhs buffer should not be empty ");
        };

        for lhs_chunk in lhs_buffer.drain(..) {
            for rhs_chunk in rhs_buffer.drain(..) {
                yield Self::build_chunk(
                    data_types,
                    lhs_mapping,
                    rhs_mapping,
                    lhs_chunk.clone(),
                    rhs_chunk,
                )?;
            }
        }
    }

    fn build_chunk(
        data_types: &[DataType],
        lhs_mapping: &ColIndexMapping,

View on GitHub (pinned to 6469eb736d)