dbt-labs/dbt-core · error
metadata query plan always includes metadata SQL
Error message
metadata query plan always includes metadata SQL
What it means
In `freshness_inner_with_options` (crates/dbt-adapter/src/metadata/snowflake/mod.rs:640), the code builds a metadata query plan via `snowflake_metadata_query_plan` and asserts `.statements.last()` exists. The panic means the plan builder returned an empty statement list, violating its contract that the metadata SQL is always appended last.
Source
Thrown at crates/dbt-adapter/src/metadata/snowflake/mod.rs:640
Box::new(AdapterConnectionFactory::new(
self.adapter.engine().clone(),
self.adapter.engine().threads(),
)),
));
let adapter = self.adapter.clone();
let token_clone = token.clone();
let map_f = move |conn: &'_ mut dyn Connection,
database_and_where_clauses: &(String, Vec<String>)|
-> AdapterResult<Arc<RecordBatch>> {
let (database, where_clauses) = &database_and_where_clauses;
let sql = snowflake_freshness_sql(database, where_clauses)?;
let plan = snowflake_metadata_query_plan(&sql, metadata_warehouse.as_deref());
let metadata_sql = plan
.statements
.last()
.expect("metadata query plan always includes metadata SQL");
let ctx = QueryCtx::default().with_desc("Extracting freshness from information schema");
let (_adapter_response, agate_table) =
adapter.query(&ctx, conn, metadata_sql, None, token_clone.clone())?;
let batch = agate_table.original_record_batch();
Ok(batch)
};
let reduce_f = move |acc: &mut Acc,
database_and_where_clauses: (String, Vec<String>),
batch_res: AdapterResult<Arc<RecordBatch>>|
-> Result<(), Cancellable<AdapterError>> {
let Ok(batch) = batch_res else {
// Keep successful database batches; missing relations fall back downstream.
return Ok(());
};
let schemas = batch.column_values::<StringArray>("TABLE_SCHEMA")?;
let tables = batch.column_values::<StringArray>("TABLE_NAME")?;View on GitHub (pinned to 0267ce9170)
Solutions
- Fix snowflake_metadata_query_plan to always append the metadata SQL statement (return an error on empty instead)
- Replace `.expect` with error propagation reporting the empty plan
- Add a unit test asserting the plan always ends with the metadata statement
- Check that snowflake_freshness_sql is not producing empty SQL for the given inputs
Example fix
// before
.expect("metadata query plan always includes metadata SQL")
// after
.ok_or_else(|| AdapterError::new(AdapterErrorKind::UnexpectedResult, "empty metadata query plan".into()))? Defensive patterns
Strategy: validation
Validate before calling
// preflight: plan must be non-empty
let plan = snowflake_metadata_query_plan(&sql, warehouse);
if plan.statements.is_empty() { return Err(/* error */); } Type guard
fn plan_has_metadata_sql(plan: &QueryPlan) -> bool {
!plan.statements.is_empty()
} Try / catch
let metadata_sql = plan.statements.last().ok_or_else(|| AdapterError::new(...))?;
Prevention
- Unit-test snowflake_metadata_query_plan always appends metadata SQL
- Reject empty freshness SQL before planning
- Keep plan-builder refactor tests in CI
- Log generated SQL on anomalous plans
When it happens
Trigger: `snowflake_metadata_query_plan` returning a plan with zero statements — typically after a refactor of the plan builder or an empty/invalid freshness SQL input it silently accepts.
Common situations: Post-refactor regressions in snowflake_metadata_query_plan; edge-case where the freshness SQL builder produced empty SQL that the planner dropped; feature flags stripping warehouse-prefix statements.
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
- validated above
- Schema not found for canonical FQN: {}
- `EnterGuard` values dropped out of order. Guards returned by
- {e} {:?}
- {e}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/ca88e6f3284e42aa.
Report an issue: GitHub.