{"record":{"id":"ca88e6f3284e42aa","repo":"dbt-labs/dbt-core","slug":"metadata-query-plan-always-includes-metadata-sql","errorCode":null,"errorMessage":"metadata query plan always includes metadata SQL","messagePattern":"metadata query plan always includes metadata SQL","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/metadata/snowflake/mod.rs","lineNumber":640,"sourceCode":"            Box::new(AdapterConnectionFactory::new(\n                self.adapter.engine().clone(),\n                self.adapter.engine().threads(),\n            )),\n        ));\n\n        let adapter = self.adapter.clone();\n        let token_clone = token.clone();\n        let map_f = move |conn: &'_ mut dyn Connection,\n                          database_and_where_clauses: &(String, Vec<String>)|\n              -> AdapterResult<Arc<RecordBatch>> {\n            let (database, where_clauses) = &database_and_where_clauses;\n            let sql = snowflake_freshness_sql(database, where_clauses)?;\n\n            let plan = snowflake_metadata_query_plan(&sql, metadata_warehouse.as_deref());\n            let metadata_sql = plan\n                .statements\n                .last()\n                .expect(\"metadata query plan always includes metadata SQL\");\n\n            let ctx = QueryCtx::default().with_desc(\"Extracting freshness from information schema\");\n            let (_adapter_response, agate_table) =\n                adapter.query(&ctx, conn, metadata_sql, None, token_clone.clone())?;\n            let batch = agate_table.original_record_batch();\n            Ok(batch)\n        };\n\n        let reduce_f = move |acc: &mut Acc,\n                             database_and_where_clauses: (String, Vec<String>),\n                             batch_res: AdapterResult<Arc<RecordBatch>>|\n              -> Result<(), Cancellable<AdapterError>> {\n            let Ok(batch) = batch_res else {\n                // Keep successful database batches; missing relations fall back downstream.\n                return Ok(());\n            };\n            let schemas = batch.column_values::<StringArray>(\"TABLE_SCHEMA\")?;\n            let tables = batch.column_values::<StringArray>(\"TABLE_NAME\")?;","sourceCodeStart":622,"sourceCodeEnd":658,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/metadata/snowflake/mod.rs#L622-L658","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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"],"exampleFix":"// before\n.expect(\"metadata query plan always includes metadata SQL\")\n// after\n.ok_or_else(|| AdapterError::new(AdapterErrorKind::UnexpectedResult, \"empty metadata query plan\".into()))?","handlingStrategy":"validation","validationCode":"// preflight: plan must be non-empty\nlet plan = snowflake_metadata_query_plan(&sql, warehouse);\nif plan.statements.is_empty() { return Err(/* error */); }","typeGuard":"fn plan_has_metadata_sql(plan: &QueryPlan) -> bool {\n    !plan.statements.is_empty()\n}","tryCatchPattern":"let metadata_sql = plan.statements.last().ok_or_else(|| AdapterError::new(...))?;","preventionTips":["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"],"tags":["rust","panic","snowflake","freshness"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}