PRQL/prql · error · Error

expected , found

Error message

expected {expected}, found `{found}`

What it means

`pl::Expr::try_cast` is a helper in the semantic module: callers pass a closure that attempts to destructure an expression kind, and if it does not match, the error reports who/what was expected and the actual found expression. It is the generic 'wrong expression shape' error reused across the resolver and lowering for casts like 'expected a string literal'.

Solutions

  1. Read the `expected` field in the message and supply an expression of that shape
  2. Replace non-literal values with literal ones where the language requires literals
  3. Check the function signature in std declarations for the expected argument type

Example fix

// before
interval 1_day_part  # wrong shape
// after
interval 1 day
Defensive patterns

Strategy: type-guard

Validate before calling

// Validate literal-ness before calling APIs that require literals
function requireLiteral(value, kind) {
  if (typeof value !== kind.expectedJsType) {
    throw new Error(`expected ${kind.name} literal, got ${typeof value}`);
  }
}

Type guard

function isStringLiteral(expr) {
  return expr && expr.kind === "literal" && typeof expr.value === "string";
}

Try / catch

try {
  compile(query);
} catch (e) {
  if (/^expected .+, found/.test(e.message)) {
    console.error("Expression shape mismatch — supply the literal/kind named in `expected`:", e.message);
  } else { throw e; }
}

Prevention

When it happens

Trigger: Any resolver code path calling `try_cast` with an expression that does not match the required kind, e.g. passing a non-literal where a literal is required (`interval` arguments, sstring parts, named args, etc.).

Common situations: Using a variable instead of a literal where PRQL requires a constant (e.g. `date`/`interval` components), or writing `"x"` where a number is expected and similar.

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/856a4d1667f65c6a. Report an issue: GitHub.

Appendix: source

Thrown at prqlc/prqlc/src/semantic/mod.rs:142

    pub(crate) fn name(&self) -> &str {
        match &self.kind {
            StmtKind::QueryDef(_) => NS_QUERY_DEF,
            StmtKind::VarDef(VarDef { name, .. }) => name,
            StmtKind::TypeDef(TypeDef { name, .. }) => name,
            StmtKind::ModuleDef(ModuleDef { name, .. }) => name,
            StmtKind::ImportDef(ImportDef { name, alias }) => alias.as_ref().unwrap_or(&name.name),
        }
    }
}

impl pl::Expr {
    fn try_cast<T, F, S2: ToString>(self, f: F, who: Option<&str>, expected: S2) -> Result<T, Error>
    where
        F: FnOnce(pl::ExprKind) -> Result<T, pl::ExprKind>,
    {
        f(self.kind).map_err(|i| {
            Error::new(Reason::Expected {
                who: who.map(|s| s.to_string()),
                expected: expected.to_string(),
                found: format!("`{}`", write_pl(pl::Expr::new(i))),
            })
            .with_span(self.span)
        })
    }
}

/// Write a PL IR to string.
///
/// Because PL needs to be restricted back to AST, ownerships of expr is required.
pub fn write_pl(expr: pl::Expr) -> String {
    let expr = ast_expand::restrict_expr(expr);

    crate::codegen::write_expr(&expr)
}
#[cfg(test)]

View on GitHub (pinned to e164e249b9)