dbt-labs/dbt-core · error · InvalidOperation
Method '{method}' did not return a Table when called on a Ta
Error message
Method '{method}' did not return a Table when called on a TableSet What it means
AgateTableSet._proxy fans a method call out to every table in the set and expects each underlying table to return an AgateTable. If any table's method result cannot be downcast to an AgateTable, this InvalidOperation error is thrown instead of proceeding. It signals the proxied method produced a value of an unexpected type for at least one member table.
Source
Thrown at crates/dbt-agate/src/table_set.rs:216
/// def _proxy(self, method_name, *args, **kwargs):
/// """
/// Calls a method on each table in this :class:`.TableSet`.
/// """
/// ```
fn _proxy(
self: &Arc<Self>,
state: &State<'_, '_>,
method: &str,
args: &[Value],
listeners: &[Rc<dyn RenderingEventListener>],
) -> Result<Arc<Self>, Error> {
let mut tables: Vec<Arc<AgateTable>> = Vec::with_capacity(self.tables.len());
for table in self.tables.iter() {
let new_table = table
.call_method(state, method, args, listeners)?
.downcast_object::<AgateTable>()
.ok_or_else(|| {
Error::new(
ErrorKind::InvalidOperation,
format!(
"Method '{}' did not return a Table when called on a TableSet",
method
),
)
})?;
tables.push(new_table);
}
self._fork(tables, self.keys.clone(), None, None)
}
fn tables_as_tuple(self: &Arc<Self>) -> TableSetTablesAsTuple {
TableSetTablesAsTuple::of_tableset(self)
}
fn keys_as_tuple(self: &Arc<Self>) -> TableSetKeysAsTuple {
TableSetKeysAsTuple::of_tableset(self)View on GitHub (pinned to 0267ce9170)
Solutions
- Verify the method name is one that returns a Table (e.g. aggregate-style table-to-table operations), not a scalar-returning method.
- Call the method on individual tables via table.call_method and inspect the returned object type before using TableSet.
- If a custom method is registered, ensure it returns an AgateTable-wrapped object.
- Check for version mismatches between the method registry and the TableSet proxy code.
Example fix
// before tables.call_method(state, "column_names", args) // returns a list, not a Table // after tables.call_method(state, "join", args) // use a method that returns a Table
Defensive patterns
Strategy: type-guard
Type guard
// verify result is a table before use
let obj = table.call_method(state, method, args)?;
if obj.downcast_object::<AgateTable>().is_none() {
// handle non-table result, e.g. skip or fall back to per-table calls
} Prevention
- Only proxy methods documented to return a Table through TableSet.
- Test new/registered methods against a TableSet, not just a single table.
When it happens
Trigger: Calling TableSet.call_method (via _proxy) with a method name whose implementation returns something other than an AgateTable (e.g. a computed column value, a scalar, or a different object type) for one of the tables in the set.
Common situations: Passing a jinja/agate method name that is only valid on non-table objects; a custom or patched method returning a scalar; version drift where a method's return type changed.
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
- role must be a string
- get_csv_data: argument must be an AgateTable
- remote_state must be Object
- 'primary_key' has a wrong type in StaticBaseRelationObject:
- Invalid arguments to doc macro
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/6aa81d9b21f6eb8e.
Report an issue: GitHub.