dbt-labs/dbt-core · error
AgateTable exists
Error message
AgateTable exists
What it means
`convert_macro_result_to_record_batch` (crates/dbt-adapter/src/macro_exec.rs:44) expects a macro result dynamic object to be either a `ResultObject` with a non-None `table` or an `AgateTable`. The `.expect("AgateTable exists")` panics when a `ResultObject` is returned whose `table` field is None — i.e. the macro produced a result without a table.
Source
Thrown at crates/dbt-adapter/src/macro_exec.rs:44
execute_macro_with_package(state, args, macro_name, "dbt")
}
pub fn execute_macro_wrapper_with_package(
state: &State,
args: &[Value],
macro_name: &str,
package: &str,
) -> Result<Arc<RecordBatch>, AdapterError> {
let result: Value = execute_macro_with_package(state, args, macro_name, package)?;
convert_macro_result_to_record_batch(&result)
}
pub fn convert_macro_result_to_record_batch(
result: &Value,
) -> Result<Arc<RecordBatch>, AdapterError> {
// Depending on the macro impl, result can be either ResultObject or AgateTable
let table = if let Some(result) = result.downcast_object::<ResultObject>() {
result.table.as_ref().expect("AgateTable exists").to_owned()
} else if let Some(result) = result.downcast_object::<AgateTable>() {
result.as_ref().to_owned()
} else {
return Err(AdapterError::new(
AdapterErrorKind::UnexpectedResult,
format!("Unexpected result type {result}"),
));
};
let record_batch = table.original_record_batch();
Ok(record_batch)
}
pub fn execute_macro_with_package(
state: &State,
args: &[Value],
macro_name: &str,
package: &str,View on GitHub (pinned to 0267ce9170)
Solutions
- Fix the macro to always set a table on its `ResultObject`
- Change the code to handle `result.table` being None by returning an `AdapterError` (or empty RecordBatch) instead of `.expect`
- Check which macro implementation was dispatched and verify its return contract
- Guard callers: only invoke this conversion for macros documented to return tables
Example fix
// before
result.table.as_ref().expect("AgateTable exists").to_owned()
// after
result.table.as_ref().map(|t| t.to_owned()).ok_or_else(|| {
AdapterError::new(AdapterErrorKind::UnexpectedResult, "macro ResultObject has no table".into())
})? Defensive patterns
Strategy: type-guard
Validate before calling
// check macro result shape before conversion
let ok = result.downcast_object::<ResultObject>().map(|r| r.table.is_some()).unwrap_or(false)
|| result.downcast_object::<AgateTable>().is_some();
if !ok { return Err(/* UnexpectedResult */); } Type guard
fn has_convertible_table(result: &Value) -> bool {
result.downcast_object::<ResultObject>().map_or(false, |r| r.table.is_some())
|| result.downcast_object::<AgateTable>().is_some()
} Try / catch
std::panic::catch_unwind(AssertUnwindSafe(|| convert_macro_result_to_record_batch(&result)))
Prevention
- Ensure dispatched macros always set ResultObject.table
- Document each macro's return contract
- Test custom macros through the adapter wrapper
- Handle the UnexpectedResult branch before calling conversion
When it happens
Trigger: Calling any of `get_columns_in_relation_via_macro`, `try_columns_from_json_describe`, `execute_macro_wrapper_with_package`, `fetch_json_metadata`, `fetch_catalog_data` when the executed macro returns a `ResultObject` with `table: None` (or an unsupported third type, which yields the UnexpectedResult error instead).
Common situations: A custom/dispatched macro variant returns a plain value or empty result instead of a table; a macro was refactored to return JSON metadata without a table; adapter package versions disagree on the macro's return shape.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Schema not found for canonical FQN: {}
- `EnterGuard` values dropped out of order. Guards returned by
- {e} {:?}
- {e}
- inconsistent park state; actual = {actual}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/3a94878f08cb1ca7.
Report an issue: GitHub.