{"record":{"id":"2f1751c7737516c0","repo":"BoundaryML/baml","slug":"expected-string-value-for-tag-key","errorCode":null,"errorMessage":"Expected string value for tag key {}","messagePattern":"Expected string value for tag key (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/language_client_cffi/src/ctypes/function_args_decode.rs","lineNumber":72,"sourceCode":"            .type_builder\n            .map(RawPtrType::decode)\n            .transpose()?\n            .map(|r| match r {\n                RawPtrType::TypeBuilder(t) => Ok(t),\n                other => Err(anyhow::anyhow!(\n                    \"Expected TypeBuilder, got {}\",\n                    other.name()\n                )),\n            })\n            .transpose()?;\n\n        let tags = from\n            .tags\n            .into_iter()\n            .map(|v| {\n                from_host_kv_to_baml_kv(v).and_then(|(k, v)| match v {\n                    BamlValue::String(s) => Ok((k, s)),\n                    _ => anyhow::bail!(\"Expected string value for tag key {}\", k),\n                })\n            })\n            .collect::<Result<_, _>>()?;\n\n        Ok(BamlFunctionArguments {\n            kwargs,\n            client_registry,\n            env_vars,\n            collectors,\n            type_builder,\n            tags,\n        })\n    }\n}\n\nimpl Decode for ClientRegistry {\n    type From = crate::baml::cffi::HostClientRegistry;\n","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_cffi/src/ctypes/function_args_decode.rs#L54-L90","documentation":"Thrown while decoding the tags field of BamlFunctionArguments: each tag entry is decoded via from_host_kv_to_baml_kv and must carry a BamlValue::String. If the decoded value is any other BamlValue variant (int, bool, map, etc.), the decode fails naming the offending tag key.","triggerScenarios":"Passing non-string tag values (numbers, booleans, objects) in the tags argument of a BAML function call, e.g. tags={\"attempt\": 3} instead of {\"attempt\": \"3\"}.","commonSituations":"Developers attaching observability/metadata tags with natural numeric or boolean values, or templating that substitutes unquoted values into tag maps.","solutions":["Convert all tag values to strings on the host side before passing them (e.g. str(value) or String(value))","If richer values are needed, flatten them into multiple string tags (e.g. \"attempt\": \"3\")","Add a host-side validator for the tags map that rejects non-string values with a clearer message"],"exampleFix":"// before (Python)\ntags = {\"attempt\": 3}\n\n// after\ntags = {\"attempt\": str(3)}  # or \"3\"","handlingStrategy":"validation","validationCode":"def validate_tags(tags):\n    bad = {k: type(v).__name__ for k, v in tags.items() if not isinstance(v, str)}\n    if bad:\n        raise TypeError(f\"Tag values must be strings, fix: {bad}\")\n    return {k: str(v) for k, v in tags.items()}\n\ntags = validate_tags(tags)","typeGuard":"def all_string_values(d: dict) -> bool:\n    return all(isinstance(v, str) for v in d.values())","tryCatchPattern":"try:\n    result = client.CallFunction(fn, args)\nexcept Exception as e:\n    if \"Expected string value for tag key\" in str(e):\n        raise TypeError(\"Coerce tag values to strings, e.g. {'attempt': '3'}\") from e\n    raise","preventionTips":["Treat tags as a string-to-string map by convention","Coerce numeric/boolean tag values with str() at call sites","Validate tags once in a shared helper used by all BAML invocations"],"tags":["ffi","decode","tags","type-mismatch","rust"],"backgroundTag":"type-mismatch","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}