PRQL/prql · error · Error

parameter `rolling`: expected a number, found

Error message

parameter `rolling`: expected a number, found {found}

What it means

The `rolling` parameter of the `window` transform must be an integer literal specifying the rolling window size. When the resolver cannot read it as an integer literal (it is a float, string, boolean, or expression), it throws this error naming the parameter and printing the found expression.

Solutions

  1. Pass a plain integer literal, e.g. `rolling:3`
  2. Remove quotes around numeric values
  3. Inline any variable value as a literal, since window sizes are resolved at compile time

Example fix

// before
window rolling:"3" (sum amount)
// after
window rolling:3 (sum amount)
Defensive patterns

Strategy: validation

Validate before calling

const rolling = 3;
if (!Number.isInteger(rolling)) {
  throw new Error("rolling must be an integer literal");
}

Type guard

const isIntLit = (v) => typeof v === "number" && Number.isInteger(v);

Try / catch

try { prql_compile(query); } catch (e) { if (e.message.includes("parameter `rolling`")) { /* replace rolling arg with an integer literal */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling `window rolling:<expr>` where the argument is not an integer literal — e.g. `rolling:3.5`, `rolling:"3"`, `rolling:n` for a variable, or `rolling:2+1`.

Common situations: Quoting the window size; using a float; trying to parameterize the window with a variable (not supported at compile time); copying SQL `ROWS BETWEEN` syntax.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


AI-assisted analysis of PRQL/prql@e164e249b9 (2026-09-09). Data as JSON: /api/errors/9498abd864337902. Report an issue: GitHub.

Appendix: source

Thrown at prqlc/prqlc/src/semantic/resolver/transforms.rs:180

                let expanding = {
                    let as_bool = expanding.kind.as_literal().and_then(|l| l.as_boolean());

                    *as_bool.ok_or_else(|| {
                        Error::new(Reason::Expected {
                            who: Some("parameter `expanding`".to_string()),
                            expected: "a boolean".to_string(),
                            found: write_pl(expanding.clone()),
                        })
                        .with_span(expanding.span)
                    })?
                };

                let rolling = {
                    let as_int = rolling.kind.as_literal().and_then(|x| x.as_integer());

                    *as_int.ok_or_else(|| {
                        Error::new(Reason::Expected {
                            who: Some("parameter `rolling`".to_string()),
                            expected: "a number".to_string(),
                            found: write_pl(rolling.clone()),
                        })
                        .with_span(rolling.span)
                    })?
                };

                let rows = {
                    let range_tuple = try_restrict_range(rows).map_err(|expr| {
                        Error::new(Reason::Expected {
                            who: Some("parameter `rows`".to_string()),
                            expected: "a range".to_string(),
                            found: write_pl(expr.clone()),
                        })
                        .with_span(expr.span)
                    })?;
                    into_literal_range(range_tuple)?

View on GitHub (pinned to e164e249b9)