{"record":{"id":"025b0d0dd3d86001","repo":"dbt-labs/dbt-core","slug":"get-table-options-failed-to-deserialize-config","errorCode":null,"errorMessage":"get_table_options: Failed to deserialize config: {e}","messagePattern":"get_table_options: Failed to deserialize config: (.+?)","errorType":"exception","errorClass":"minijinja::Error::SerdeDeserializeError","httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/adapter/mod.rs","lineNumber":2104,"sourceCode":"    #[tracing::instrument(skip(self, state), level = \"trace\")]\n    pub fn get_table_options(\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(\"get_table_options\", &[\"config\", \"node\"], args);\n                let config_val = iter.next_arg::<&Value>()?;\n                let node_val = iter.next_arg::<&Value>()?;\n                let temporary = iter\n                    .next_kwarg::<Option<bool>>(\"temporary\")?\n                    .unwrap_or_default();\n                iter.finish()?;\n\n                let config = minijinja_value_to_typed_struct::<ModelConfig>(config_val.clone())\n                    .map_err(|e| {\n                        minijinja::Error::new(\n                            minijinja::ErrorKind::SerdeDeserializeError,\n                            format!(\"get_table_options: Failed to deserialize config: {e}\"),\n                        )\n                    })?;\n                let node = minijinja_value_to_typed_struct::<InternalDbtNodeWrapper>(\n                    node_val.clone(),\n                )\n                .map_err(|e| {\n                    minijinja::Error::new(\n                        minijinja::ErrorKind::SerdeDeserializeError,\n                        format!(\n                            \"get_table_options: Failed to deserialize InternalDbtNodeWrapper: {e}\"\n                        ),\n                    )\n                })?;\n\n                let options = adapter.get_table_options(state, config, &node, temporary)?;\n                Ok(Value::from_serialize(options))","sourceCodeStart":2086,"sourceCodeEnd":2122,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/adapter/mod.rs#L2086-L2122","documentation":"`get_table_options` deserializes the `config` argument into `ModelConfig` and, unlike the other call sites, prefixes the serde failure with `get_table_options: Failed to deserialize config:` as a minijinja `SerdeDeserializeError`. It means the model config object passed from Jinja does not conform to the ModelConfig struct the adapter expects.","triggerScenarios":"Calling `adapter.get_table_options(config=<value>, node=..., temporary=...)` where config is a plain dict missing required ModelConfig fields or containing keys/values of the wrong type.","commonSituations":"Custom materialization macros passing a hand-built config dict instead of the node's `config` object; project vars injecting unexpected keys; adapter version changes to ModelConfig fields breaking older macros.","solutions":["Read the prefixed message to identify the exact field/type mismatch.","Pass the model's real `config` object (e.g. `model.config`) rather than a reconstructed dict.","Remove or fix keys with wrong types in the config (quote strings, use booleans for flags).","Diff the config against the adapter's ModelConfig fields for the installed version.","Update custom materializations/macros to the current adapter API."],"exampleFix":"// before (Jinja)\n{% set opts = adapter.get_table_options(config={'k': 'v'}, node=node) %}\n// after\n{% set opts = adapter.get_table_options(config=model.config, node=node) %}","handlingStrategy":"validation","validationCode":"{# Jinja #}\n{% if config is not mapping %}\n  {{ exceptions.raise_compiler_error('get_table_options requires a config mapping') }}\n{% endif %}\n{% set opts = adapter.get_table_options(config=model.config, node=node) %}","typeGuard":"fn is_model_config(v: &minijinja::Value) -> bool {\n    minijinja_value_to_typed_struct::<ModelConfig>(v.clone()).is_ok()\n}","tryCatchPattern":"{% try %}\n  {% set opts = adapter.get_table_options(config=cfg, node=node) %}\n{% except %}\n  {{ log('get_table_options config invalid: ' ~ cfg | tojson, info=true) }}\n{% endtry %}","preventionTips":["Always pass the node's real config object, never a hand-built dict","Validate custom materialization macros against ModelConfig after upgrades","Debug with `{{ config | tojson }}` to inspect the value's shape"],"tags":["serde","adapter","config","materialization","deserialization"],"backgroundTag":"schema-validation-failed","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"}