BoundaryML/baml · error
Failed to decode BamlValue
Error message
Failed to decode BamlValue
What it means
Thrown inside BamlMethodArguments::decode when a kwargs entry has a valid string key but its `value` field is None, so Value::decode cannot be performed. The generic message does not name the key because the guard is a simple None match on the value.
Source
Thrown at engine/language_client_cffi/src/ctypes/object_args_decode.rs:38
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: from
.kwargs
.into_iter()
.map(|v| {
let key = match v.key {View on GitHub (pinned to bd85ce9dee)
Solutions
- Encode nulls explicitly as a null Value (per the bindings' null representation) instead of leaving the protobuf field unset
- Omit None-valued kwargs from the map entirely rather than passing entries without values
- Upgrade host bindings/runtime together so optional value serialization is consistent
Example fix
// before (Python)
kwargs = {"options": None}
client.CallMethod("m", kwargs)
// after
kwargs = {k: v for k, v in kwargs.items() if v is not None}
client.CallMethod("m", kwargs) Defensive patterns
Strategy: validation
Validate before calling
clean_kwargs = {k: v for k, v in kwargs.items() if v is not None}
# or, if nulls are meaningful, use the bindings' explicit null value
clean_kwargs = {k: (v if v is not None else baml_null) for k, v in kwargs.items()} Type guard
def all_kwargs_encoded(kwargs: dict) -> bool:
return all(v is not _unset_sentinel for v in kwargs.values()) Try / catch
try:
result = obj.CallMethod(method, kwargs)
except Exception as e:
if "Failed to decode BamlValue" in str(e):
raise ValueError("A kwarg had no encoded value; pass an explicit null or drop the entry") from e
raise Prevention
- Never pass sentinel/unset values in kwargs; encode nulls explicitly
- Strip or fill None-valued parameters before FFI calls
- Regenerate bindings whenever the cffi schema changes
When it happens
Trigger: A method-call kwarg is present with no encoded value — e.g. passing None/null values that the serializer drops instead of encoding as an explicit null Value.
Common situations: Calling BAML object methods with None-valued parameters, bindings that serialize absent optional fields by omission, or hand-built HostMapEntry objects in tests missing the value.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Key is missing
- Value is null for key {}
- Value is null for key {}
- Key must be a string
- Protobuf decode error: {0}
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/874b7ae81196b186.
Report an issue: GitHub.