risingwavelabs/risingwave · error · ParserError

ROWS, RANGE, or GROUPS

Error message

ROWS, RANGE, or GROUPS

What it means

This error is raised by `parse_window_frame_units` when the parser cannot recognize the frame unit keyword of a window frame clause (OVER ... ROWS/RANGE/GROUPS/SESSION). The `dispatch!` combinator only accepts ROWS, RANGE, GROUPS or SESSION; anything else fails and `.expect(...)` converts that failure into a user-facing 'expected ROWS, RANGE, or GROUPS' message. It is a SQL syntax error reporting that a window frame unit keyword was required but not found.

Source

Thrown at src/sqlparser/src/parser.rs:914

        Ok(Expr::Function(Function {
            scalar_as_agg,
            name,
            arg_list,
            within_group,
            filter,
            over,
        }))
    }

    pub fn parse_window_frame_units(&mut self) -> ModalResult<WindowFrameUnits> {
        dispatch! { peek(keyword);
            Keyword::ROWS => keyword.value(WindowFrameUnits::Rows),
            Keyword::RANGE => keyword.value(WindowFrameUnits::Range),
            Keyword::GROUPS => keyword.value(WindowFrameUnits::Groups),
            Keyword::SESSION => keyword.value(WindowFrameUnits::Session),
            _ => fail,
        }
        .expect("ROWS, RANGE, or GROUPS")
        .parse_next(self)
    }

    pub fn parse_window_frame(&mut self) -> ModalResult<WindowFrame> {
        let units = self.parse_window_frame_units()?;
        let bounds = if self.parse_keyword(Keyword::BETWEEN) {
            // `BETWEEN <frame_start> AND <frame_end>`
            let start = self.parse_window_frame_bound()?;
            self.expect_keyword(Keyword::AND)?;
            let end = Some(self.parse_window_frame_bound()?);
            WindowFrameBounds::Bounds { start, end }
        } else if self.parse_keywords(&[Keyword::WITH, Keyword::GAP]) {
            // `WITH GAP <gap>`, only for session frames
            WindowFrameBounds::Gap(Box::new(self.parse_expr()?))
        } else {
            // `<frame_start>`
            WindowFrameBounds::Bounds {
                start: self.parse_window_frame_bound()?,

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Fix the window frame unit keyword to one of ROWS, RANGE, GROUPS (or SESSION in this dialect), e.g. `OVER (ORDER BY x ROWS BETWEEN 1 PRECEDING AND CURRENT ROW)`.
  2. Ensure the frame clause actually contains a unit keyword before BETWEEN or the bound expression.
  3. If the query came from another database, rewrite its frame clause to the supported unit keywords.

Example fix

// before
SELECT sum(v) OVER (ORDER BY t ROW BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t;
// after
SELECT sum(v) OVER (ORDER BY t ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) FROM t;
Defensive patterns

Strategy: validation

Validate before calling

const FRAME_UNITS = new Set(['ROWS','RANGE','GROUPS','SESSION']);
function validFrameUnit(unit) { return FRAME_UNITS.has(unit.toUpperCase()); }

Type guard

const isFrameUnit = (s) => typeof s === 'string' && ['ROWS','RANGE','GROUPS','SESSION'].includes(s.toUpperCase());

Prevention

When it happens

Trigger: Parsing a query with a window frame whose unit token is misspelled, missing, or unsupported, e.g. `OVER (ROWS ...)` missing nothing but written as `OVER (ROW BETWEEN ...)` or `OVER (PARTITION BY x ORDER BY y BETWEEN ...)` where the unit keyword is absent before BETWEEN/UNBOUNDED.

Common situations: Hand-written SQL with typos in window frame clauses; SQL dialects where window frames use different keywords; generated SQL from ORMs or query builders that emit nonstandard frame syntax; porting queries from other engines with exotic frame specs.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/26214308c68e08f2. Report an issue: GitHub.