{"record":{"id":"3d424bec85a6cc05","repo":"risingwavelabs/risingwave","slug":"rhs-chunk-cardinality-should-be-1-or-2","errorCode":null,"errorMessage":"rhs chunk cardinality should be 1 or 2","messagePattern":"rhs chunk cardinality should be 1 or 2","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/row_merge.rs","lineNumber":153,"sourceCode":"                    lhs_chunk.clone(),\n                    rhs_chunk,\n                )?;\n            }\n        }\n    }\n\n    fn build_chunk(\n        data_types: &[DataType],\n        lhs_mapping: &ColIndexMapping,\n        rhs_mapping: &ColIndexMapping,\n        lhs_chunk: StreamChunk,\n        rhs_chunk: StreamChunk,\n    ) -> Result<Message, StreamExecutorError> {\n        if !(1..=2).contains(&lhs_chunk.cardinality()) {\n            bail!(\"lhs chunk cardinality should be 1 or 2\");\n        }\n        if !(1..=2).contains(&rhs_chunk.cardinality()) {\n            bail!(\"rhs chunk cardinality should be 1 or 2\");\n        }\n        if lhs_chunk.cardinality() != rhs_chunk.cardinality() {\n            bail!(\"lhs and rhs chunk cardinality should be the same\");\n        }\n        let cardinality = lhs_chunk.cardinality();\n        let mut ops = Vec::with_capacity(cardinality);\n        let mut merged_rows = vec![vec![Datum::None; data_types.len()]; cardinality];\n        for (i, (op, lhs_row)) in lhs_chunk.rows().enumerate() {\n            ops.push(op);\n            for (j, d) in lhs_row.iter().enumerate() {\n                // NOTE(kwannoel): Unnecessary columns will not have a mapping,\n                // for instance extra row count column.\n                // those can be skipped here.\n                if let Some(out_index) = lhs_mapping.try_map(j) {\n                    merged_rows[i][out_index] = d.to_owned_datum();\n                }\n            }\n        }","sourceCodeStart":135,"sourceCodeEnd":171,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/row_merge.rs#L135-L171","documentation":"The rhs counterpart of the lhs cardinality check in `build_chunk`: rhs chunks must contain exactly 1 or 2 rows so they can be merged row-by-row with lhs chunks of the same cardinality. Any other size breaks the pairwise merge contract.","triggerScenarios":"Internal: rhs chunk with cardinality 0 or >2 reaches `build_chunk` because upstream chunk splitting on the right side did not enforce the 1–2 row size.","commonSituations":"Same as lhs case: upstream chunking regressions, bypassed split logic, or direct invocations in tests.","solutions":["Log `rhs_chunk.cardinality()` and file an issue with the pipeline definition","Recreate the streaming job to reset executor state","Upgrade RisingWave for possible row_merge fixes","In tests, split rhs chunks to cardinality 1–2 before calling build_chunk"],"exampleFix":"// before\nMessage::Chunk(rhs_big_chunk)\n// after\nfor c in split_chunk(rhs_big_chunk, 2) { Message::Chunk(c) }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match build_result {\n    Err(e) if e.to_string().contains(\"rhs chunk cardinality should be 1 or 2\") => {\n        // Right-side chunking invariant broken: report and recreate\n        report_issue_with_chunk_trace();\n        recreate_streaming_job(job_id);\n    }\n    other => other?,\n}","preventionTips":["Ensure upstream right-side chunks are split to 1–2 rows before merging","Keep custom executor/test wiring consistent with the 1–2 row contract","Watch release notes for chunking regressions affecting row_merge","Recreate affected jobs to clear bad buffered chunks"],"tags":["rust","streaming","internal-invariant","row-merge"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}