dbt-labs/dbt-core · error

RelationConfig should serialize

Error message

RelationConfig should serialize

What it means

Test panic from `serialize_object(&original).expect("RelationConfig should serialize")` in serializable_impls.rs:463. `serialize_object` goes through the time-machine registry (TYPE_ID-based); it returns None/errors when the value's concrete type is not registered for serialization or a component cannot be rendered back to JSON. This panic means a freshly deserialized RelationConfig cannot be written back to recording JSON for its Databricks relation type.

Source

Thrown at crates/dbt-adapter/src/time_machine/serializable_impls.rs:463

                RelationType::MaterializedView,
                serde_json::json!({
                    "partitioned_by": {"partition_by": ["event_date"]}
                }),
            ),
            (
                RelationType::StreamingTable,
                serde_json::json!({
                    "comment": {"comment": "streaming events", "persist": true},
                    "partitioned_by": {"partition_by": ["event_date"]}
                }),
            ),
        ];

        for (relation_type, payload) in cases {
            let ctx = databricks_ctx(relation_type);
            let original = RelationConfig::from_time_machine_json(&payload, &ctx)
                .expect("RelationConfig should deserialize");
            let recorded = serialize_object(&original).expect("RelationConfig should serialize");
            let restored = json_to_value_with_context(&recorded, &ctx);
            assert_eq!(
                serialize_object(&restored),
                Some(recorded),
                "RelationConfig should roundtrip for {relation_type:?}"
            );
        }
    }

    /// Reproduces the Databricks same-version replay break.
    ///
    /// `tbl_properties::to_jinja` emits TWO keys for the `tblproperties` component:
    /// the `tblproperties` sub-map (with `pipelines.pipelineId` filtered out) AND a
    /// separate top-level `pipeline_id`. But `component_from_recorded` only reads back
    /// `val.get("tblproperties")` — the `pipeline_id` is silently dropped on deserialize.
    ///
    /// For any DLT-backed relation (streaming tables, materialized views), the recorded
    /// `pipeline_id` is a non-null string. On replay the recorded result is deserialized

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Confirm RelationConfig::TYPE_ID is registered in the time-machine serialization registry (see test_type_ids_are_stable).
  2. Check serialize_object's per-relation-type branches cover all RelationTypes used in the test (Table, View, MaterializedView, StreamingTable).
  3. Add the missing component serialization (to_jinja/to recorded JSON path) for the failing relation type.
  4. Return the registry lookup error instead of Option so failures are diagnosable, then rerun the test.

Example fix

// before
let recorded = serialize_object(&original).expect("RelationConfig should serialize");
// after
let recorded = serialize_object(&original)
    .unwrap_or_else(|| panic!("RelationConfig failed to serialize for {relation_type:?}"));
Defensive patterns

Strategy: try-catch

Validate before calling

if RelationConfig::TYPE_ID_registry_missing() {
    panic!("RelationConfig not registered for time-machine serialization");
}

Type guard

fn serializable(v: &minijinja::Value) -> bool {
    serialize_object(v).is_some()
}

Try / catch

let recorded = serialize_object(&original).unwrap_or_else(|| {
    log::error("RelationConfig unserializable for this relation type");
    fallback_to_raw_payload()
});

Prevention

When it happens

Trigger: `serialize_object` called on a RelationConfig whose TYPE_ID (`RelationConfig`) is missing from the registry, or whose per-relation-type components (tags, column_tags, tblproperties, partitioned_by, comment) cannot be converted to recorded JSON for the ctx's RelationType.

Common situations: Forgetting to register RelationConfig (or a new component) in the time-machine serialization registry after refactoring; a component only implemented for some RelationTypes (e.g. tblproperties on Table but not View); ctx.with_relation_type set to a type the serializer has no branch for.

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/5f15dbb49577f32f. Report an issue: GitHub.