{"record":{"id":"98e71804ac8a4d2b","repo":"dbt-labs/dbt-core","slug":"grants-table-must-be-an-agatetable","errorCode":null,"errorMessage":"grants_table must be an AgateTable","messagePattern":"grants_table must be an AgateTable","errorType":"exception","errorClass":"minijinja::Error::InvalidOperation","httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/adapter/mod.rs","lineNumber":514,"sourceCode":"    /// def standardize_grants_dict(\n    ///     self,\n    ///     grants_table: \"agate.Table\"\n    /// ) -> dict\n    /// ```\n    #[tracing::instrument(skip_all, level = \"trace\")]\n    pub fn standardize_grants_dict(\n        &self,\n        _state: &State,\n        args: &[Value],\n    ) -> Result<Value, minijinja::Error> {\n        match &self.inner {\n            Typed { adapter, .. } => {\n                let iter = ArgsIter::new(\"standardize_grants_dict\", &[\"grants_table\"], args);\n                let grants_table = iter\n                    .next_arg::<&Value>()?\n                    .downcast_object::<AgateTable>()\n                    .ok_or_else(|| {\n                        minijinja::Error::new(\n                            minijinja::ErrorKind::InvalidOperation,\n                            \"grants_table must be an AgateTable\",\n                        )\n                    })?;\n\n                Ok(Value::from_serialize(\n                    &adapter.standardize_grants_dict(grants_table)?,\n                ))\n            }\n            // This method is typically called after show grants SQL + run_query.\n            // During parse phase, run_query returns Undefined since queries don't execute,\n            // so we don't have an actual AgateTable. Return an empty grants dict to avoid\n            // downcast errors on Undefined values.\n            Parse(_) => Ok(Value::from(BTreeMap::<Value, Vec<Value>>::new())),\n        }\n    }\n\n    /// Build catalog from show tables and svv columns","sourceCodeStart":496,"sourceCodeEnd":532,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/adapter/mod.rs#L496-L532","documentation":"`standardize_grants_dict` expects its `grants_table` argument to be a Minijinja Value wrapping an `AgateTable` object. The library throws this InvalidOperation error when the value cannot be downcast to AgateTable. This guards the Rust side against being handed arbitrary Jinja values (dicts, lists, strings) in place of an agate table of GRANT rows.","triggerScenarios":"Calling the `standardize_grants_dict` adapter function from Jinja/Python with a `grants_table` argument that is a plain dict/list/string rather than an AgateTable — typically when hand-building the grants result instead of using `load_agate_table()`.","commonSituations":"Custom grant macros (get_grant.sql) return raw query results converted incorrectly, or a custom adapter override passes a serialized dict of grant rows where an AgateTable is expected.","solutions":["Convert the grants query result to an AgateTable before calling (e.g. `load_agate_table()` in the macro's Python wrapper)","Verify the macro signature order: grants_table must be the first positional arg bound to the agate table","If writing a custom adapter, ensure the value passed is `Value::from_object(AgateTable)` not `Value::from_serialize(rows)`"],"exampleFix":"// before (caller)\nadapter.standardize_grants_dict(grants_dict)\n// after\nadapter.standardize_grants_dict(load_agate_table(grants_response))","handlingStrategy":"type-guard","validationCode":"// python caller guard\nif not isinstance(grants_table, agate.Table):\n    grants_table = load_agate_table(grants_table)","typeGuard":"fn as_agate_table(v: &Value) -> Option<Arc<AgateTable>> {\n    v.downcast_object::<AgateTable>()\n}","tryCatchPattern":"match grants_value.downcast_object::<AgateTable>() {\n    Some(t) => standardize(t),\n    None => Err(Error::new(InvalidOperation, \"grants_table must be an AgateTable; wrap results with load_agate_table()\")),\n}","preventionTips":["Always convert query results via load_agate_table() before passing to adapter grant functions","Never pass serialized dicts/lists where adapter signatures expect AgateTable","Keep custom grant macro signatures identical to the built-in ones"],"tags":["grants","agate","downcast","minijinja"],"backgroundTag":"invalid-argument-value","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"}