{"record":{"id":"40a51cd9456a4b51","repo":"dbt-labs/dbt-core","slug":"should-be-able-to-serialize-job-labels","errorCode":null,"errorMessage":"Should be able to serialize job labels","messagePattern":"Should be able to serialize job labels","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/dbt-adapter/src/engine/adapter_engine.rs","lineNumber":294,"sourceCode":"        }\n        (Some(state), AdapterType::Bigquery) => {\n            let mut job_labels =\n                maybe_query_comment\n                    .as_ref()\n                    .map_or_else(IndexMap::new, |comment| {\n                        engine\n                            .query_comment()\n                            .get_job_labels_from_query_comment(comment)\n                    });\n            if let Some(invocation_id_label) = state\n                .lookup(\"invocation_id\", &[])\n                .and_then(|value| value.as_str().map(|label| label.to_owned()))\n            {\n                job_labels.insert(\"dbt_invocation_id\".to_string(), invocation_id_label);\n            }\n\n            let job_label_option =\n                serde_json::to_string(&job_labels).expect(\"Should be able to serialize job labels\");\n            options.push((\n                QUERY_LABELS.to_owned(),\n                OptionValue::String(job_label_option),\n            ));\n        }\n        _ => {}\n    }\n\n    type ExecuteOutput = (Arc<Schema>, Vec<RecordBatch>, Option<i64>);\n    let do_execute = |conn: &'_ mut dyn Connection| -> Result<\n        ExecuteOutput,\n        Cancellable<adbc_core::error::Error>,\n    > {\n        use dbt_adbc::statement::Statement as _;\n\n        let mut stmt = if engine.has_query_cache() {\n            let stmt = conn.new_statement()?;\n            engine.new_query_cache_statement(stmt).map_err(|e| {","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/engine/adapter_engine.rs#L276-L312","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","solutions":["Replace the `expect` with graceful error propagation: map the serde result into the function's error type and skip the label option on failure.","Keep job_labels restricted to `String` keys and values so serialization is infallible by construction.","Add a unit test asserting the label JSON serialization path to catch regressions early."],"exampleFix":"// before\nlet job_label_option =\n    serde_json::to_string(&job_labels).expect(\"Should be able to serialize job labels\");\n\n// after\nlet job_label_option = serde_json::to_string(&job_labels)\n    .map_err(|e| DbtAdapterError::internal(format!(\"failed to serialize job labels: {e}\")))?;","handlingStrategy":"try-catch","validationCode":"// labels are HashMap<String,String>, which is always JSON-serializable;\n// guard against refactors introducing non-string values:\nlet ok = job_labels.keys().all(|k| !k.is_empty());","typeGuard":"fn serializable_labels(labels: &HashMap<String, String>) -> bool {\n    serde_json::to_string(labels).is_ok()\n}","tryCatchPattern":"match serde_json::to_string(&job_labels) {\n    Ok(s) => options.push((QUERY_LABELS.to_owned(), OptionValue::String(s))),\n    Err(e) => log::warn!(\"skipping job labels: {e}\"),\n}","preventionTips":["Keep job label maps strictly String -> String","Replace expect on serialization with logged fallbacks","Add a regression test covering the label option path"],"tags":["panic","serde","json-serialization","rust","adbc"],"backgroundTag":"json-serialization-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"}