PRQL/prql · error · Error
expected , found
Error message
expected {expected_ty}, found {found_ty} What it means
Generic type-check failure in the resolver: an expression's inferred type did not match the type expected by a transform or function argument. The `who` context usually names the offending construct (e.g. a `std.join` argument), and special hints are added when a function was found where a non-function type was expected (e.g. forgetting to call it).
Solutions
- Read `who` and the expected/found types in the full error; align the argument's type with the expected one.
- If a function was found where a value was expected, call it: add parentheses and arguments.
- Cast or convert the value (e.g. wrap numbers in `std.int` text conversions) when types are close but not identical.
- Check the docs for the transform's argument signature (e.g. `std.join` needs tables plus join keys).
Example fix
// before join other (x -> x.id == id) // after join other (side:left, x.id == id)
Defensive patterns
Strategy: validation
Validate before calling
// check argument types against the transform signature before generating PRQL
if (!matchesExpectedType(arg.type, signature[transform][param])) throw new Error(`param ${param} of ${transform} must be ${signature[transform][param]}`); Type guard
const isFunctionExpr = (e) => e.kind === 'func' || e.kind === 'lambda'; // if isFunctionExpr(arg) and a value is expected, the call is missing invocation
Try / catch
try { compile(prql) } catch (e) { if (e.message.includes('found') && e.message.includes('expected') && e.annotations?.who?.includes('std.join')) { /* fix join argument types */ } } Prevention
- Read the `who:` context in the error to locate the offending argument
- Verify transform argument signatures in the PRQL stdlib docs
- Add parentheses when a function/lambda must be invoked rather than passed
- Run prqlc compile on generated queries in CI to catch type errors early
When it happens
Trigger: Passing a wrong-typed argument to any transform — e.g. `join side:...` receiving a non-table, comparing incompatible types in `filter`, or giving a function object where a value/column type is required.
Common situations: Joining on a non-table expression, passing a lambda where a column is expected, mixing text and numeric literals in comparisons, or forgetting parentheses to invoke a table-returning function.
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 table, found
- parameter `expanding`: expected a boolean, found
- parameter `rolling`: expected a number, found
- ` `: expected relation, found
- tuple: expected to have at least one entry when initial…
AI-assisted analysis of PRQL/prql@e164e249b9 (2026-09-09).
Data as JSON: /api/errors/6c38555dcb2b114c.
Report an issue: GitHub.
Appendix: source
Thrown at prqlc/prqlc/src/semantic/resolver/types.rs:205
{
fn display_ty(ty: &Ty) -> String {
if ty.name.is_none() {
if let TyKind::Tuple(fields) = &ty.kind {
if fields.len() == 1 && fields[0].is_wildcard() {
return "a tuple".to_string();
}
}
}
format!("type `{}`", write_ty(ty))
}
let who = who();
let is_join = who
.as_ref()
.map(|x| x.contains("std.join"))
.unwrap_or_default();
let mut e = Error::new(Reason::Expected {
who,
expected: display_ty(expected),
found: display_ty(found_ty),
});
if found_ty.kind.is_function() && !expected.kind.is_function() {
let found = found_ty.kind.as_function().unwrap();
let func_name = if let Some(func) = found {
func.name_hint.as_ref()
} else {
None
};
let to_what = func_name
.map(|n| format!("to function {n}"))
.unwrap_or_else(|| "in this function call".to_string());
e = e.push_hint(format!("Argument might be missing {to_what}?"));
}View on GitHub (pinned to e164e249b9)