PRQL/prql · error · Error
expected a table, found
Error message
expected a table, found {found_desc} What it means
A pipeline stage that requires a table (e.g. `from`) was given an expression that is not a table. When the found expression has no relation id — for instance a bare lambda like `x -> y` or a plain function — the resolver reports what kind of thing it actually found instead of 'a table'.
Solutions
- Call the function if it returns a table: `from (my_func arg)` rather than `from my_func`.
- Replace the lambda/function with an actual table reference, e.g. `from employees`.
- Check the expression's type: it must be a relation/table to sit in a `from` position.
Example fix
// before from (x -> x) // after from employees
Defensive patterns
Strategy: type-guard
Validate before calling
// ensure the argument is a table reference before putting it in `from`
if (typeof source !== 'string' && !isTableCall(source)) throw new Error('from requires a table'); Type guard
const isTableRef = (e) => typeof e === 'string' || (e.kind === 'ident' && !e.isLambda && !e.isFunc);
Try / catch
try { compile(prql) } catch (e) { if (e.message.includes('expected a table')) { /* replace the expression with a table or call the function */ } } Prevention
- Only place table-typed expressions after `from` or as relation arguments
- Call table-returning functions with parentheses instead of passing them bare
- Don't use bare lambdas in pipeline source positions
When it happens
Trigger: Writing `from (x -> y)` (bare lambda), `from some_function`, or piping a function/literal into a transform that expects a relation rather than a table-typed expression.
Common situations: Confusing functions/lambdas with relations, forgetting to call a function that returns a table, or passing a scalar expression where a table is required.
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 , 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/f706843fecf09f83.
Report an issue: GitHub.
Appendix: source
Thrown at prqlc/prqlc/src/semantic/resolver/types.rs:111
return Ok(());
};
let Some(found_ty) = &mut found.ty else {
// found is none: infer from expected
if found.lineage.is_none() && expected.unwrap().is_relation() {
// special case: infer a table type
// inferred tables are needed for s-strings that represent tables
// similarly as normal table references, we want to be able to infer columns
// of this table, which means it needs to be defined somewhere
// in the module structure.
let Some(id) = found.id else {
// Expression has no id - this happens with bare lambdas like `x -> y`
let found_desc = match &found.kind {
ExprKind::Func(_) => "a function".to_string(),
kind => format!("{kind:?}"),
};
return Err(Error::new(Reason::Expected {
who: None,
expected: "a table".to_string(),
found: found_desc,
})
.with_span(found.span));
};
let frame = self.declare_table_for_literal(id, None, found.alias.clone());
// override the empty frame with frame of the new table
found.lineage = Some(frame)
}
// base case: infer expected type
found.ty = expected.cloned();
return Ok(());
};View on GitHub (pinned to e164e249b9)