PRQL/prql · error · Error
expected a table or query, found an empty array `[]`
Error message
expected a table or query, found an empty array `[]`
What it means
During function resolution, arguments that must be relations (frames with lineage) are checked. A bare empty array `[]` used directly as a pipeline input (e.g. `from []`) has no lineage, so instead of an opaque internal bug the compiler gives this targeted error explaining that empty arrays are not valid tables.
Solutions
- Remove the empty array and use a real table via `from`
- Create data with `std.from_text` (e.g. `from_text format:csv "a,b\n1,2"`) instead of a bare array
- If the array is computed, ensure it is non-empty or route it through a function that sets lineage
Example fix
// before from [] // after from_text format:csv "a\n1"
Defensive patterns
Strategy: validation
Validate before calling
function validateRelationArg(arg) {
if (Array.isArray(arg) && arg.length === 0) {
throw new Error("empty array is not a table; use from_text or a real table");
}
} Type guard
function isEmptyArrayLiteral(expr) {
return expr && expr.kind === "array" && expr.items.length === 0;
} Try / catch
try {
compile(query);
} catch (e) {
if (e.message.includes("an empty array")) {
console.error("Build literal data with std.from_text instead of [].");
} else { throw e; }
} Prevention
- Never pass [] or {} directly to from/join
- Use std.from_text for inline data
- Verify computed sources are non-empty before compiling
When it happens
Trigger: `from []`, `join []`, or passing `[]` to any std function expecting a relation, without going through functions like `std.from_text` that set lineage.
Common situations: Building test queries with literal data via wrong means, or forgetting to use `from_text`/`sql` to turn literal data into a table.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- expected , found
- expected a type, found
- expected a value, found a type
- expected a table or query, found an empty tuple
- {}
AI-assisted analysis of PRQL/prql@e164e249b9 (2026-09-09).
Data as JSON: /api/errors/3ba5634f19895cb7.
Report an issue: GitHub.
Appendix: source
Thrown at prqlc/prqlc/src/semantic/resolver/functions.rs:274
.fold_and_type_check(arg, param, func_name)?
.unwrap_or_else(|a| {
partial_application_position = Some(index);
a
});
}
log::debug!("resolved arg to {}", arg.kind.as_ref());
resolved_relations.push((index, arg, is_last));
}
// Then, add relation frames into scope
for (index, arg, is_last) in resolved_relations {
if partial_application_position.is_none() {
let frame = arg.lineage.as_ref().ok_or_else(|| {
// Provide helpful error for empty arrays/tuples used directly
// (not from functions like std.from_text which set lineage properly)
match &arg.kind {
ExprKind::Array(v) if v.is_empty() => Error::new(Reason::Expected {
who: None,
expected: "a table or query".to_string(),
found: "an empty array `[]`".to_string(),
})
.with_span(arg.span),
ExprKind::Tuple(v) if v.is_empty() => Error::new(Reason::Expected {
who: None,
expected: "a table or query".to_string(),
found: "an empty tuple `{}`".to_string(),
})
.with_span(arg.span),
_ => Error::new_bug(4317).with_span(closure.body.span),
}
})?;
if is_last {
self.root_mod.module.insert_frame(frame, NS_THIS);
} else {
self.root_mod.module.insert_frame(frame, NS_THAT);View on GitHub (pinned to e164e249b9)