{"record":{"id":"469b1aafad2a6973","repo":"BoundaryML/baml","slug":"key-must-be-a-string-object-args-decode","errorCode":null,"errorMessage":"Key must be a string","messagePattern":"Key must be a string","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/language_client_cffi/src/ctypes/object_args_decode.rs","lineNumber":34,"sourceCode":"impl Decode for BamlMethodArguments {\n    type From = crate::baml::cffi::BamlObjectMethodInvocation;\n\n    fn decode(from: Self::From) -> Result<Self, anyhow::Error> {\n        Ok(BamlMethodArguments {\n            object: match from.object.map(RawPtrType::decode).transpose()? {\n                Some(object) => object,\n                None => {\n                    return Err(anyhow::anyhow!(\"Failed to decode RawPtrType for object\"));\n                }\n            },\n            method_name: from.method_name,\n            kwargs: from\n                .kwargs\n                .into_iter()\n                .map(|v| {\n                    let key = match v.key {\n                        Some(crate::baml::cffi::host_map_entry::Key::StringKey(k)) => k,\n                        _ => return Err(anyhow::anyhow!(\"Key must be a string\")),\n                    };\n                    match v.value {\n                        Some(value) => Ok((key, Value::decode(value)?)),\n                        None => Err(anyhow::anyhow!(\"Failed to decode BamlValue\")),\n                    }\n                })\n                .collect::<Result<_, _>>()?,\n        })\n    }\n}\n\nimpl Decode for BamlObjectConstructorArgs {\n    type From = crate::baml::cffi::BamlObjectConstructorInvocation;\n\n    fn decode(from: Self::From) -> Result<Self, anyhow::Error> {\n        Ok(BamlObjectConstructorArgs {\n            object_type: BamlObjectType::try_from(from.r#type)?,\n            kwargs: from","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_cffi/src/ctypes/object_args_decode.rs#L16-L52","documentation":"Thrown inside BamlMethodArguments::decode while converting the method's kwargs: a HostMapEntry key must be a StringKey, and any other variant (int/bool/enum/unset) is rejected with this fixed message. Method kwargs are String-keyed by contract.","triggerScenarios":"Passing a kwargs entry with a non-string key (e.g. numeric or boolean keys in the host dict) to a BAML object method call.","commonSituations":"Python dicts keyed by ints, JS objects produced from numeric-key JSON, or generated code building kwargs programmatically with non-string keys.","solutions":["Coerce all kwargs keys to strings before calling the method (e.g. {str(k): v for k, v in kwargs.items()})","Fix data sources (JSON parsing, DB rows) that produce non-string keys and normalize at construction time","Add a host-side assertion that kwargs keys are strings before crossing the FFI boundary"],"exampleFix":"// before (Python)\nkwargs = {42: \"answer\"}\n\n// after\nkwargs = {str(k): v for k, v in kwargs.items()}","handlingStrategy":"validation","validationCode":"def normalize_kwargs(kwargs):\n    if not all(isinstance(k, str) for k in kwargs):\n        raise TypeError(\"Method kwargs keys must be strings\")\n    return {str(k): v for k, v in kwargs.items()}\n\nkwargs = normalize_kwargs(raw_kwargs)","typeGuard":"def has_string_keys(d: dict) -> bool:\n    return all(isinstance(k, str) for k in d)","tryCatchPattern":"try:\n    result = obj.CallMethod(method, kwargs)\nexcept Exception as e:\n    if \"Key must be a string\" in str(e):\n        raise TypeError(\"Stringify all kwargs keys before the FFI call\") from e\n    raise","preventionTips":["Normalize keys to strings where data enters your app (JSON.parse reviver, DB adapters)","Avoid int/bool keyed dicts as parameter maps","Add a shared kwargs sanitizer for all BAML method calls"],"tags":["ffi","decode","kwargs","map-keys","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-14T11:17:12.474Z"}