BoundaryML/baml · error
failed to unmarshal FFI response: %w
Error message
failed to unmarshal FFI response: %w
What it means
decodeAsyncResponse wraps every FFI reply from the native BAML runtime: the C buffer bytes are unmarshaled as a protobuf InvocationResponse. When the bytes are not a valid protobuf message (truncated buffer, corrupt memory, version-skewed proto schema between Go client and native library), this error wraps the proto.Unmarshal failure with %w.
Source
Thrown at engine/language_client_go/baml_go/exports.go:88
C.WrapRegisterCallbacks((C.CallbackFn)(callbackFn), (C.CallbackFn)(errorFn), (C.OnTickCallbackFn)(onTickFn))
return nil
}
// decodeAsyncResponse decodes a Buffer containing an InvocationResponse.
// Returns nil on success, or an error if the response contains an error.
func decodeAsyncResponse(buf C.Buffer) error {
defer C.WrapFreeBuffer(buf)
// Empty buffer means success (task was spawned)
if buf.ptr == nil || buf.len == 0 {
return nil
}
content_bytes := C.GoBytes(unsafe.Pointer(buf.ptr), C.int32_t(buf.len))
var response cffi.InvocationResponse
if err := proto.Unmarshal(content_bytes, &response); err != nil {
return fmt.Errorf("failed to unmarshal FFI response: %w", err)
}
// Check if response contains an error
switch response.GetResponse().(type) {
case *cffi.InvocationResponse_Error:
return fmt.Errorf("%s", response.GetError())
default:
// Success or nil response means success
return nil
}
}
func CallFunctionFromC(runtime unsafe.Pointer, functionName string, encodedArgs []byte, id uint32) error {
cFunctionName := C.CString(functionName)
defer C.free(unsafe.Pointer(cFunctionName))
cEncodedArgs := (*C.char)(unsafe.Pointer(&encodedArgs[0]))
View on GitHub (pinned to bd85ce9dee)
Solutions
- Rebuild or re-download the BAML shared library so it matches the Go client version (delete the cached library in os.UserCacheDir()/baml and let it re-download)
- Check that VERSION in the Go package matches the version reported by the loaded native library (BamlVmVersion check in initializeBaml)
- If reproducible, report/capture the raw buffer length; a zero-length or truncated buffer points to a native-side bug
- Pin baml-go and the native library to identical versions in CI to avoid drift
Example fix
// before // cached old .so downloaded months ago, mismatched with upgraded baml-go // after // rm -rf "$(go env GOENV-cache-dir)/baml" and rebuild so findOrDownloadLibrary fetches the matching library
Defensive patterns
Strategy: try-catch
Validate before calling
libVer, err := baml.LoadedLibraryVersion() _ = libVer // compare against expected client version before making calls
Try / catch
resp, err := baml.CallFunctionFromC(...)
if err != nil && strings.Contains(err.Error(), "failed to unmarshal FFI response") {
// native/Go version skew: re-download matching library and retry init
return baml.Reinitialize()
} Prevention
- Never mix baml-go versions with stale cached native libraries; clear the cache on upgrade
- Pin identical client/library versions in CI
- Treat repeated unmarshal failures as a version-skew alarm, not a transient error
When it happens
Trigger: Any call through CallFunctionFromC, CallFunctionStreamFromC, CallFunctionParseFromC, BuildRequestFromC, or CancelFunctionCall where the returned C buffer does not decode as a cffi.InvocationResponse protobuf.
Common situations: Mixing a Go baml-go client version with a differently-built native shared library so the proto definitions differ; the native side returning an error object instead of a serialized response; memory corruption in the FFI boundary.
Understand the failure class
Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.
Related errors
- failed to unmarshal content bytes: %w
- Protobuf decode error: {0}
- Map entry missing key
- Invalid InboundValue.value_type: a root union or optional do
- Key is missing
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/1499365d633f5abc.
Report an issue: GitHub.