{"record":{"id":"7dedb6f7b9c159bc","repo":"risingwavelabs/risingwave","slug":"session-gap-should-be-non-negative-but-is-give","errorCode":null,"errorMessage":"session gap should be non-negative, but {} is given","messagePattern":"session gap should be non-negative, but (.+?) is given","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/expr/core/src/window_function/session.rs","lineNumber":91,"sourceCode":"}\n\nimpl Display for SessionFrameBounds {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        write!(\n            f,\n            \"SESSION WITH GAP {}\",\n            self.gap.as_scalar_ref_impl().to_text()\n        )\n    }\n}\n\nimpl FrameBoundsImpl for SessionFrameBounds {\n    fn validate(&self) -> Result<()> {\n        // TODO(rc): maybe can merge with `RangeFrameBounds::validate`\n\n        fn validate_non_negative(val: impl IsNegative + Display) -> Result<()> {\n            if val.is_negative() {\n                bail!(\"session gap should be non-negative, but {} is given\", val);\n            }\n            Ok(())\n        }\n\n        match self.gap.as_scalar_ref_impl() {\n            ScalarRefImpl::Int16(val) => validate_non_negative(val)?,\n            ScalarRefImpl::Int32(val) => validate_non_negative(val)?,\n            ScalarRefImpl::Int64(val) => validate_non_negative(val)?,\n            ScalarRefImpl::Float32(val) => validate_non_negative(val)?,\n            ScalarRefImpl::Float64(val) => validate_non_negative(val)?,\n            ScalarRefImpl::Decimal(val) => validate_non_negative(val)?,\n            ScalarRefImpl::Interval(val) => {\n                if !val.is_never_negative() {\n                    bail!(\n                        \"for session gap of type `interval`, each field should be non-negative, but {} is given\",\n                        val\n                    );\n                }","sourceCodeStart":73,"sourceCodeEnd":109,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/expr/core/src/window_function/session.rs#L73-L109","documentation":"A session window's gap defines the maximum inactivity distance between rows; a negative gap is meaningless because sessions can only extend forward in time. During frame bounds validation, each gap value (across int16/int32/int64/float32/float64/decimal/interval types) is checked for negativity and rejected.","triggerScenarios":"Creating a session window frame whose gap literal/expression evaluates to a negative value, e.g. `SESSION('5 seconds'::interval)` with `-'1 second'` or a negative numeric gap, caught during `validate` at plan/exec construction.","commonSituations":"Typo or sign error in session gap constant; gap derived from a computed expression that can go negative; bad parameterized values bound at runtime.","solutions":["Use a positive gap value (e.g. INTERVAL '5 seconds')","If the gap is computed, clamp it: `greatest(gap_expr, 0)`","Add a frontend/SQL-side check that rejects negative gaps with a friendly message before reaching the executor"],"exampleFix":"// before\nCREATE ... SESSION('−1 second'::interval)\n// after\nCREATE ... SESSION('1 second'::interval)","handlingStrategy":"validation","validationCode":"// SQL-side guard\n-- reject: gap < 0\n-- use: greatest(gap_expr, INTERVAL '0 seconds')","typeGuard":"fn non_negative_gap(g: ScalarImpl) -> bool { !g.as_scalar_ref_impl().unwrap().is_negative() }","tryCatchPattern":"match build_session_frame(gap) {\n    Err(e) if e.to_string().contains(\"non-negative\") => return Err(anyhow!(\"session gap must be >= 0\")),\n    other => other,\n}","preventionTips":["Wrap user-supplied gaps with greatest(gap, 0)","Reject negative gaps at SQL parse/planning time","Never compute the gap from expressions that can go negative without clamping"],"tags":["rust","window-function","session-window","validation"],"backgroundTag":"invalid-argument-value","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"}