{"record":{"id":"59eb208370cd1420","repo":"risingwavelabs/risingwave","slug":"unreachable-non-comparator","errorCode":null,"errorMessage":"unreachable (non-comparator)","messagePattern":"unreachable \\(non-comparator\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/executor/dynamic_filter.rs","lineNumber":241,"sourceCode":"            (Some(c), None) | (None, Some(c)) => {\n                let range = match self.comparator {\n                    GreaterThan => (Excluded(c), Unbounded),\n                    GreaterThanOrEqual => (Included(c), Unbounded),\n                    LessThan => (Unbounded, Excluded(c)),\n                    LessThanOrEqual => (Unbounded, Included(c)),\n                    _ => unreachable!(),\n                };\n                let is_insert = curr_is_some;\n                // The new bound is always towards the last known value\n                let is_lower = matches!(self.comparator, GreaterThan | GreaterThanOrEqual);\n                (range, is_lower, is_insert)\n            }\n            (Some(c), Some(p)) => {\n                if c.default_cmp(&p).is_lt() {\n                    let range = match self.comparator {\n                        GreaterThan | LessThanOrEqual => (Excluded(c), Included(p)),\n                        GreaterThanOrEqual | LessThan => (Included(c), Excluded(p)),\n                        _ => unreachable!(),\n                    };\n                    let is_insert = matches!(self.comparator, GreaterThan | GreaterThanOrEqual);\n                    (range, true, is_insert)\n                } else {\n                    // c > p\n                    let range = match self.comparator {\n                        GreaterThan | LessThanOrEqual => (Excluded(p), Included(c)),\n                        GreaterThanOrEqual | LessThan => (Included(p), Excluded(c)),\n                        _ => unreachable!(),\n                    };\n                    let is_insert = matches!(self.comparator, LessThan | LessThanOrEqual);\n                    (range, false, is_insert)\n                }\n            }\n            (None, None) => unreachable!(), // prev != curr\n        }\n    }\n","sourceCodeStart":223,"sourceCodeEnd":259,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/executor/dynamic_filter.rs#L223-L259","documentation":"In get_range's (Some(c), Some(p)) branch where the current value c is less than the previous value p, the code maps the comparator to a decreasing range. Only the four ordering comparators are handled; any other comparator value triggers `unreachable!()`. Like the sibling panics, this indicates the executor was built with an unsupported comparison node type.","triggerScenarios":"execute_inner calls get_range when both the previous and current right-side values are non-null and c.default_cmp(&p).is_lt() (the watermark moved backwards / decreased), while self.comparator is not GreaterThan/GreaterThanOrEqual/LessThan/LessThanOrEqual.","commonSituations":"Encountered during development of new comparator kinds or when a planner bug passes a wrong PbExprNodeType; the decreasing-value branch is hit when the compared column (often an event-time/ingestion timestamp) can regress.","solutions":["Confirm the executor construction only ever uses the four ordering comparators (add a debug_assert in new()).","If a new comparator is intended, extend this match arm and the other two in get_range consistently.","Log the comparator value before the panic (or convert to an internal error) to make the misconfiguration diagnosable."],"exampleFix":"// before\n_ => unreachable!(),\n// after\nother => return Err(StreamExecutorError::internal(anyhow::anyhow!(\n    \"get_range: unsupported comparator {:?} for decreasing bound\", other\n))),","handlingStrategy":"validation","validationCode":"debug_assert!(matches!(self.comparator, GreaterThan | GreaterThanOrEqual | LessThan | LessThanOrEqual), \"bad comparator: {:?}\", self.comparator);","typeGuard":"fn is_ordering_comparator(c: &PbExprNodeType) -> bool {\n    matches!(c, PbExprNodeType::GreaterThan | PbExprNodeType::GreaterThanOrEqual | PbExprNodeType::LessThan | PbExprNodeType::LessThanOrEqual)\n}","tryCatchPattern":"let range = match self.comparator {\n    GreaterThan | LessThanOrEqual => (Excluded(c), Included(p)),\n    GreaterThanOrEqual | LessThan => (Included(c), Excluded(p)),\n    other => return Err(StreamExecutorError::internal(anyhow::anyhow!(\"unsupported comparator {:?}\", other))),\n};","preventionTips":["Keep a single helper that validates the comparator once at construction, not at every match site.","Add tests covering decreasing right-value transitions for each supported comparator.","Replace bare unreachable!() with descriptive internal errors during development."],"tags":["rust","panic","executor","comparator","match-arm"],"backgroundTag":"invalid-enum-value","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"}