BoundaryML/baml · error
Invalid object type
Error message
Invalid object type
What it means
The baml_cffi_macros generated decoder converts an optional C object pointer (RawPtrType / BamlObjectHandle) back into the Rust wrapper type via generated match arms. `None` means the source object pointer was null or of an unexpected handle kind, so there is no representation to decode — reported as 'Invalid object type'.
Solutions
- Ensure the caller passes a valid, non-null BamlObjectHandle obtained from the corresponding encode/constructor call
- Check that the handle's type tag matches the Rust type being decoded into
- Re-verify the enum of object types passed to generate_encode_decode_impls includes the type you are decoding
- Add debug logging of the handle tag at the decode boundary to identify mismatches
Example fix
// before
let value = MyType::decode(handle)?; // panics/errors on wrong or null handle
// after
if handle.is_null() {
return Err(anyhow::anyhow!("received null BamlObjectHandle"));
}
let value = MyType::decode(handle)
.map_err(|e| anyhow::anyhow!("decode failed for handle {:?}: {e}", handle.kind()))?; Defensive patterns
Strategy: try-catch
Validate before calling
if handle.is_null() { return Err(anyhow!("null BamlObjectHandle")); } Type guard
fn is_valid_handle(h: &BamlObjectHandle) -> bool { !h.as_ptr().is_null() && h.kind() == ExpectedKind::MyType } Try / catch
let value = MyType::decode(handle).context("failed to decode handle from C boundary")?; Prevention
- Always round-trip handles through the matching encode/decode pair
- Null-check pointers at every FFI entry point
- Regenerate CFFI impls after adding or reordering object types
When it happens
Trigger: Calling the generated decode() on a BamlObjectHandle whose inner object is None (null pointer), or whose tag does not correspond to any decode arm generated for the type.
Common situations: FFI callers passing a null or already-freed handle across the C boundary; a handle created for a different baml object type being fed to the wrong decode impl after macro/enum changes.
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
- Expected Collector, got
- Expected string value for tag key
- Expected TypeBuilder, got
- Failed to decode BamlValue
- Failed to decode RawPtrType for object
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/0d36aba4b5937859.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml_cffi_macros/src/lib.rs:1622
}
})
} else {
None
}
})
.collect();
let expanded = quote! {
impl Decode for RawPtrType {
type From = BamlObjectHandle;
fn decode(from: Self::From) -> Result<Self, anyhow::Error>
where
Self: Sized,
{
match from.object {
#(#decode_arms)*
None => Err(anyhow::anyhow!("Invalid object type")),
}
}
}
impl Encode<BamlObjectHandle> for RawPtrType {
fn encode(self) -> BamlObjectHandle {
match self {
#(#encode_arms,)*
}
}
}
#(#wrapper_impls)*
};
TokenStream::from(expanded)
}
View on GitHub (pinned to bd85ce9dee)