BoundaryML/baml · error
Key must be a string
Error message
Key must be a string
What it means
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.
Source
Thrown at engine/language_client_cffi/src/ctypes/object_args_decode.rs:34
impl Decode for BamlMethodArguments {
type From = crate::baml::cffi::BamlObjectMethodInvocation;
fn decode(from: Self::From) -> Result<Self, anyhow::Error> {
Ok(BamlMethodArguments {
object: match from.object.map(RawPtrType::decode).transpose()? {
Some(object) => object,
None => {
return Err(anyhow::anyhow!("Failed to decode RawPtrType for object"));
}
},
method_name: from.method_name,
kwargs: from
.kwargs
.into_iter()
.map(|v| {
let key = match v.key {
Some(crate::baml::cffi::host_map_entry::Key::StringKey(k)) => k,
_ => return Err(anyhow::anyhow!("Key must be a string")),
};
match v.value {
Some(value) => Ok((key, Value::decode(value)?)),
None => Err(anyhow::anyhow!("Failed to decode BamlValue")),
}
})
.collect::<Result<_, _>>()?,
})
}
}
impl Decode for BamlObjectConstructorArgs {
type From = crate::baml::cffi::BamlObjectConstructorInvocation;
fn decode(from: Self::From) -> Result<Self, anyhow::Error> {
Ok(BamlObjectConstructorArgs {
object_type: BamlObjectType::try_from(from.r#type)?,
kwargs: fromView on GitHub (pinned to bd85ce9dee)
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
Example fix
// before (Python)
kwargs = {42: "answer"}
// after
kwargs = {str(k): v for k, v in kwargs.items()} Defensive patterns
Strategy: validation
Validate before calling
def normalize_kwargs(kwargs):
if not all(isinstance(k, str) for k in kwargs):
raise TypeError("Method kwargs keys must be strings")
return {str(k): v for k, v in kwargs.items()}
kwargs = normalize_kwargs(raw_kwargs) Type guard
def has_string_keys(d: dict) -> bool:
return all(isinstance(k, str) for k in d) Try / catch
try:
result = obj.CallMethod(method, kwargs)
except Exception as e:
if "Key must be a string" in str(e):
raise TypeError("Stringify all kwargs keys before the FFI call") from e
raise Prevention
- 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
When it happens
Trigger: 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.
Common situations: Python dicts keyed by ints, JS objects produced from numeric-key JSON, or generated code building kwargs programmatically with non-string keys.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Key must be a string
- Failed to decode BamlValue
- Key is missing
- Value is null for key {}
- Value is null for key {}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/469b1aafad2a6973.
Report an issue: GitHub.