{"record":{"id":"7f42686f45db188c","repo":"risingwavelabs/risingwave","slug":"invalid-row-count-state","errorCode":null,"errorMessage":"Invalid row count state: {:?}","messagePattern":"Invalid row count state: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/approx_percentile/global_state.rs","lineNumber":123,"sourceCode":"                1 => {\n                    self.cache.pos_buckets.insert(bucket_id, count as i64);\n                }\n                _ => {\n                    bail!(\"Invalid sign: {}\", sign);\n                }\n            }\n        }\n        Ok(())\n    }\n\n    async fn get_row_count_state(&self) -> StreamExecutorResult<Option<OwnedRow>> {\n        self.count_state_table.get_row(&[Datum::None; 0]).await\n    }\n\n    fn decode_row_count(row_count_state: &Option<OwnedRow>) -> StreamExecutorResult<i64> {\n        if let Some(row) = row_count_state.as_ref() {\n            let Some(datum) = row.datum_at(0) else {\n                bail!(\"Invalid row count state: {:?}\", row)\n            };\n            Ok(datum.into_int64())\n        } else {\n            Ok(0)\n        }\n    }\n}\n\n// Update\nimpl<S: StateStore> GlobalApproxPercentileState<S> {\n    pub fn apply_chunk(&mut self, chunk: StreamChunk) -> StreamExecutorResult<()> {\n        // Op is ignored here, because we only check the `delta` column inside the row.\n        // The sign of the `delta` column will tell us if we need to decrease or increase the\n        // count of the bucket.\n        for (_op, row) in chunk.rows() {\n            debug_assert_eq!(_op, Op::Insert);\n            self.apply_row(row)?;\n        }","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/approx_percentile/global_state.rs#L105-L141","documentation":"`decode_row_count` reads the persisted row-count state of an approx_percentile aggregator and expects the single state row to carry an Int64 datum at position 0. If the row exists but has a NULL first datum, the state is malformed and this error is raised.","triggerScenarios":"Recovery/init of an approx_percentile global aggregator where the row-count state table contains a row whose only column is NULL — e.g. state written incompletely before a crash or by an incompatible writer version.","commonSituations":"Crash between inserting an empty row and filling it, RisingWave version upgrades changing state schema, or corrupted state store data.","solutions":["Drop and recreate the materialized view using approx_percentile to reset its state tables.","Verify the RW versions that wrote and read the state match; if an upgrade is involved, re-ingest the data instead of recovering state.","Inspect the state table for the actor via internal catalog/tools and confirm the row is NULL; if reproducible, report as a state-writer bug.","Fall back to restoring from a backup/snapshot of the state store taken when the data was valid."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Recreate approx_percentile materialized views after version upgrades.","Ensure clean shutdowns; avoid killing compute nodes mid-checkpoint.","Verify state table rows are non-empty and typed before relying on recovery."],"tags":["streaming","state-corruption","approx-percentile","recovery"],"backgroundTag":"schema-validation-failed","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}