dbt-labs/dbt-core · warning

Should be able to serialize job labels

Error message

Should be able to serialize job labels

What it means

In `adbc_execute_with_options`, job labels are collected into a map and serialized with `serde_json::to_string`, unwrapping with `expect("Should be able to serialize job labels")`. Since the labels are plain String keys/values, serialization can practically never fail, but if it did (serde error), the code panics instead of handling it.

Source

Thrown at crates/dbt-adapter/src/engine/adapter_engine.rs:294

        }
        (Some(state), AdapterType::Bigquery) => {
            let mut job_labels =
                maybe_query_comment
                    .as_ref()
                    .map_or_else(IndexMap::new, |comment| {
                        engine
                            .query_comment()
                            .get_job_labels_from_query_comment(comment)
                    });
            if let Some(invocation_id_label) = state
                .lookup("invocation_id", &[])
                .and_then(|value| value.as_str().map(|label| label.to_owned()))
            {
                job_labels.insert("dbt_invocation_id".to_string(), invocation_id_label);
            }

            let job_label_option =
                serde_json::to_string(&job_labels).expect("Should be able to serialize job labels");
            options.push((
                QUERY_LABELS.to_owned(),
                OptionValue::String(job_label_option),
            ));
        }
        _ => {}
    }

    type ExecuteOutput = (Arc<Schema>, Vec<RecordBatch>, Option<i64>);
    let do_execute = |conn: &'_ mut dyn Connection| -> Result<
        ExecuteOutput,
        Cancellable<adbc_core::error::Error>,
    > {
        use dbt_adbc::statement::Statement as _;

        let mut stmt = if engine.has_query_cache() {
            let stmt = conn.new_statement()?;
            engine.new_query_cache_statement(stmt).map_err(|e| {

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Replace the `expect` with graceful error propagation: map the serde result into the function's error type and skip the label option on failure.
  2. Keep job_labels restricted to `String` keys and values so serialization is infallible by construction.
  3. Add a unit test asserting the label JSON serialization path to catch regressions early.

Example fix

// before
let job_label_option =
    serde_json::to_string(&job_labels).expect("Should be able to serialize job labels");

// after
let job_label_option = serde_json::to_string(&job_labels)
    .map_err(|e| DbtAdapterError::internal(format!("failed to serialize job labels: {e}")))?;
Defensive patterns

Strategy: try-catch

Validate before calling

// labels are HashMap<String,String>, which is always JSON-serializable;
// guard against refactors introducing non-string values:
let ok = job_labels.keys().all(|k| !k.is_empty());

Type guard

fn serializable_labels(labels: &HashMap<String, String>) -> bool {
    serde_json::to_string(labels).is_ok()
}

Try / catch

match serde_json::to_string(&job_labels) {
    Ok(s) => options.push((QUERY_LABELS.to_owned(), OptionValue::String(s))),
    Err(e) => log::warn!("skipping job labels: {e}"),
}

Prevention

When it happens

Trigger: Only when `serde_json::to_string(&job_labels)` returns Err — essentially impossible for a `HashMap<String, String>`, but theoretically reachable via a custom serializer issue, poisoned allocator, or future refactors putting non-string-serializable values into `job_labels`.

Common situations: Refactors that add non-JSON-serializable values (e.g. non-string keys, maps with struct values) to job labels; running in an environment where serde_json's fallible path is somehow triggered; debugging unexpected panics during ADBC query execution.

Understand the failure class

Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.

Related errors


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