{"record":{"id":"05a2f7f690e4fc10","repo":"BoundaryML/baml","slug":"unification-error","errorCode":null,"errorMessage":"Unification error","messagePattern":"Unification error","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"engine/baml-lib/baml-types/src/baml_value.rs","lineNumber":1244,"sourceCode":"    /// The baml value calling `zip_meta` is the \"primary\" one, whose value\n    /// data will live on in the returned baml value.\n    pub fn zip_meta<U: Clone + std::fmt::Debug>(\n        self,\n        other: &BamlValueWithMeta<U>,\n    ) -> Result<BamlValueWithMeta<(T, U)>>\n    where\n        T: std::fmt::Debug,\n    {\n        let other_meta: U = other.meta().clone();\n        let error_msg = String::new();\n        let ret = match (self, other) {\n            (BamlValueWithMeta::Null(meta1), _) => {\n                Result::<_, _>::Ok(BamlValueWithMeta::Null((meta1, other_meta)))\n            }\n            (BamlValueWithMeta::String(s1, meta1), BamlValueWithMeta::String(_s2, _)) if true => {\n                Ok(BamlValueWithMeta::String(s1, (meta1, other_meta)))\n            }\n            (BamlValueWithMeta::String(_, _), _) => anyhow::bail!(\"Unification error\"),\n            (BamlValueWithMeta::Int(s1, meta1), BamlValueWithMeta::Int(_s2, _)) if true => {\n                Ok(BamlValueWithMeta::Int(s1, (meta1, other_meta)))\n            }\n            (BamlValueWithMeta::Int(_, _), _) => anyhow::bail!(\"Unification error\"),\n            (BamlValueWithMeta::Float(s1, meta1), BamlValueWithMeta::Float(_s2, _)) if true => {\n                Ok(BamlValueWithMeta::Float(s1, (meta1, other_meta)))\n            }\n            (BamlValueWithMeta::Float(_, _), _) => anyhow::bail!(\"Unification error\"),\n            (BamlValueWithMeta::Bool(s1, meta1), BamlValueWithMeta::Bool(_s2, _)) if true => {\n                Ok(BamlValueWithMeta::Bool(s1, (meta1, other_meta)))\n            }\n            (BamlValueWithMeta::Bool(_, _), _) => anyhow::bail!(\"Unification error\"),\n            (BamlValueWithMeta::Map(s1, meta1), BamlValueWithMeta::Map(s2, _)) => {\n                let map_result = s1\n                    .into_iter()\n                    .zip(s2)\n                    .map(|((k1, v1), (_k2, v2))| v1.zip_meta(v2).map(|res| (k1, res)))\n                    .collect::<Result<IndexMap<_, _>>>()?;","sourceCodeStart":1226,"sourceCodeEnd":1262,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/baml-types/src/baml_value.rs#L1226-L1262","documentation":"In `BamlValueWithMeta::zip_meta`, which zips two meta-annotated BAML values shape-by-shape, a `String`-vs-non-`String` pair falls into the catch-all arm `(String(_,_), _) => anyhow::bail!(\"Unification error\")`. It means the two values being unified have different BAML types at this position, so they cannot be zipped into a single value with paired metadata.","triggerScenarios":"Calling `value_a.zip_meta(value_b)` (public API) where value_a is a BamlValueWithMeta::String and value_b is Null, Int, Float, Bool, Map, List, Media, Enum, or Class.","commonSituations":"Comparing/streaming partial LLM output against an expected value where the model returned a string but the target value is a different type (or vice versa); merging results of two BAML runs whose shapes diverged.","solutions":["Verify both values' types before calling zip_meta; only zip values of the same BAML type.","Check where the two values diverge — typically one came from a parse of model output and the other from a schema/coercion step.","If a String-vs-other unification is legitimately expected, convert one side explicitly first (e.g. parse or wrap).","Capture the enclosing error_msg: zip_meta maps any failure to it, so the underlying bail is reported via that message."],"exampleFix":"// before\nlet zipped = string_value.zip_meta(other_value)?; // Unification error\n// after\nif matches!(other_value, BamlValueWithMeta::String(..)) {\n    let zipped = string_value.zip_meta(other_value)?;\n} else {\n    return Err(anyhow!(\"expected string value, got different BAML type\"));\n}","handlingStrategy":"type-guard","validationCode":"// Rust: verify both values are String-typed before zip_meta\nfn can_zip_strings(a: &BamlValueWithMeta<M1, M2>, b: &BamlValueWithMeta<M1, M2>) -> bool {\n    matches!(a, BamlValueWithMeta::String(..)) && matches!(b, BamlValueWithMeta::String(..))\n}","typeGuard":"fn as_string(v: &BamlValueWithMeta<M1, M2>) -> Option<(&str,)> {\n    if let BamlValueWithMeta::String(s, _) = v { Some((s,)) } else { None }\n}","tryCatchPattern":"// Rust\nmatch a.zip_meta(b) {\n    Ok(zipped) => use(zipped),\n    Err(e) if e.to_string().contains(\"Unification error\") => {\n        // shapes diverged: log both value types and fall back to per-type handling\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always derive both operands from the same parse/coercion pipeline so shapes match","Add a shape pre-check (same variant) before any zip_meta call","When model output may be prose, coerce to the expected type before unifying","Wrap zip_meta in a helper that returns a descriptive type-mismatch error instead of the bare 'Unification error'"],"tags":["rust","type-mismatch","baml","unification"],"backgroundTag":"type-mismatch","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}