dbt-labs/dbt-core · error
get_csv_data: argument must be an AgateTable
Error message
get_csv_data: argument must be an AgateTable
What it means
When `adapter.get_csv_data(...)` receives an argument but it cannot be downcast to the internal `AgateTable` object type, the dispatcher raises this `InvalidOperation` error. The method only understands real agate-table wrapper objects produced by the seed-loading pipeline, not plain strings, dicts, or other Value types.
Source
Thrown at crates/dbt-adapter/src/adapter/mod.rs:4371
// model: dict, settings: str -> str
Ok(args.get(1).cloned().unwrap_or_else(|| Value::from("")))
}
"get_ch_database" => {
// schema: str -> str (CH database = schema in 2-part naming)
Ok(args.first().cloned().unwrap_or_else(|| Value::from("")))
}
"get_csv_data" => {
let table = args
.first()
.ok_or_else(|| {
minijinja::Error::new(
minijinja::ErrorKind::MissingArgument,
"get_csv_data requires agate_table argument",
)
})?
.downcast_object::<AgateTable>()
.ok_or_else(|| {
minijinja::Error::new(
minijinja::ErrorKind::InvalidOperation,
"get_csv_data: argument must be an AgateTable",
)
})?;
self.get_csv_data(table)
}
"get_credentials" => self.get_credentials(args),
"render_equals" => {
let iter = ArgsIter::new(name, &["expr1", "expr2"], args);
let expr1 = iter.next_arg::<&str>()?;
let expr2 = iter.next_arg::<&str>()?;
iter.finish()?;
self.render_equals(state, expr1, expr2)
}
_ => Err(minijinja::Error::new(
minijinja::ErrorKind::UnknownMethod,
format!("Unknown method on adapter object: '{name}'"),
)),View on GitHub (pinned to 0267ce9170)
Solutions
- Pass the actual agate table object (typically the `agate_table` variable in seed macros), not a path string or dict.
- If you only have a CSV file, load it through the engine's seed-loading path to obtain an AgateTable before calling get_csv_data.
- Log/type-check the argument with `is mapping` / `is string` tests in Jinja to catch wrong inputs before dispatching.
Example fix
// before (Jinja)
{% set csv = adapter.get_csv_data(seed_file_path) %}
// after
{% set csv = adapter.get_csv_data(agate_table) %} Defensive patterns
Strategy: type-guard
Validate before calling
{# Jinja: string path or mapping means you don't have a table object #}
{% if agate_table is string or agate_table is mapping %}
{{ exceptions.raise_compiler_error("get_csv_data needs an AgateTable, not a path/dict") }}
{% endif %} Type guard
{# Jinja: AgateTable is an opaque object; reject obvious non-tables #}
{% set looks_like_table = agate_table is defined and agate_table is not string and agate_table is not mapping and agate_table is not sequence %} Prevention
- Obtain tables only from the seed-loading pipeline (the `agate_table` macro variable), not from file paths.
- Don't pass strings, dicts, or lists to adapter methods typed for table objects.
- When porting Python macros, replace agate-specific values with the engine's AgateTable wrapper.
When it happens
Trigger: Calling `adapter.get_csv_data(x)` where `x` is a string path to a CSV, a dict, a Jinja list, or any Value that is not an `AgateTable` object — for example passing `config.get('seed_path')` or the text output of another call instead of the loaded table.
Common situations: Custom macros that load CSV contents themselves and pass the raw string; confusion between a seed's file path and its parsed table; macros ported from dbt-core where the table was a Python agate object but here must be the engine's AgateTable wrapper.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- remote_state must be Object
- In adapter.dispatch, got a macro name of "{macro_name}", but
- role must be a string
- get_csv_data requires agate_table argument
- get_csv_data: failed to format CSV: {e}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/f845a684951d3c07.
Report an issue: GitHub.