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
- Read the `expected` field in the message and supply an expression of that shape
- Replace non-literal values with literal ones where the language requires literals
- 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
- Read the `expected` field of the message and match it
- Use literals where PRQL requires constants (interval/date components)
- Consult std function signatures for required argument kinds
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
- expected a type, found
- expected a value, found a type
- expected a table or query, found an empty array `[]`
- expected a table or query, found an empty tuple
- {}
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)