risingwavelabs/risingwave · error

lhs buffer should not be empty

Error message

lhs buffer should not be empty 

What it means

The row-merge executor merges buffered left and right stream chunks pairwise; `flush_buffers` is an internal invariant check that both buffers hold at least one chunk before draining. An empty lhs buffer means the merge was invoked without any left-side data staged, which indicates a scheduling bug rather than user-visible bad input.

Solutions

  1. Reproduce with debug logging of per-epoch buffer contents on both inputs and file an issue with the trace — this is an internal invariant violation
  2. Check whether the job uses two upstream fragments of unequal rate and whether recent rescale operations preceded the error; recreate the job as a workaround
  3. Upgrade RisingWave; epoch-buffer desync bugs in row_merge have been fixed across versions
  4. As mitigation, recreate the streaming job so buffer state resets
Defensive patterns

Strategy: try-catch

Try / catch

match merge_result {
    Err(e) if e.to_string().contains("lhs buffer should not be empty") => {
        // Internal epoch-buffering desync: reset executor state by recreating the job
        recreate_streaming_job(job_id);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Internal: the executor's `execute` path calls `flush_buffers` after receiving messages but never buffered an lhs chunk for the current barrier epoch — e.g. barrier/epoch bookkeeping desync between the two inputs.

Common situations: Two-input join-style executors where one side received a barrier before the other; bugs in epoch-based buffering; meta failover replaying barriers out of order.

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/5b92d975a18219bb. Report an issue: GitHub.

Appendix: source

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

                    }
                    AlignedMessage::WatermarkRight(watermark) => {
                        tracing::warn!("unexpected watermark from right stream: {:?}", watermark);
                    }
                }
            }
        }
    }

    #[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,
                )?;
            }
        }
    }

View on GitHub (pinned to 6469eb736d)