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

  1. Remove the empty array and use a real table via `from`
  2. Create data with `std.from_text` (e.g. `from_text format:csv "a,b\n1,2"`) instead of a bare array
  3. 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

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


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)