{"record":{"id":"1499365d633f5abc","repo":"BoundaryML/baml","slug":"failed-to-unmarshal-ffi-response-w","errorCode":null,"errorMessage":"failed to unmarshal FFI response: %w","messagePattern":"failed to unmarshal FFI response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"engine/language_client_go/baml_go/exports.go","lineNumber":88,"sourceCode":"\tC.WrapRegisterCallbacks((C.CallbackFn)(callbackFn), (C.CallbackFn)(errorFn), (C.OnTickCallbackFn)(onTickFn))\n\treturn nil\n}\n\n// decodeAsyncResponse decodes a Buffer containing an InvocationResponse.\n// Returns nil on success, or an error if the response contains an error.\nfunc decodeAsyncResponse(buf C.Buffer) error {\n\tdefer C.WrapFreeBuffer(buf)\n\n\t// Empty buffer means success (task was spawned)\n\tif buf.ptr == nil || buf.len == 0 {\n\t\treturn nil\n\t}\n\n\tcontent_bytes := C.GoBytes(unsafe.Pointer(buf.ptr), C.int32_t(buf.len))\n\n\tvar response cffi.InvocationResponse\n\tif err := proto.Unmarshal(content_bytes, &response); err != nil {\n\t\treturn fmt.Errorf(\"failed to unmarshal FFI response: %w\", err)\n\t}\n\n\t// Check if response contains an error\n\tswitch response.GetResponse().(type) {\n\tcase *cffi.InvocationResponse_Error:\n\t\treturn fmt.Errorf(\"%s\", response.GetError())\n\tdefault:\n\t\t// Success or nil response means success\n\t\treturn nil\n\t}\n}\n\nfunc CallFunctionFromC(runtime unsafe.Pointer, functionName string, encodedArgs []byte, id uint32) error {\n\tcFunctionName := C.CString(functionName)\n\tdefer C.free(unsafe.Pointer(cFunctionName))\n\n\tcEncodedArgs := (*C.char)(unsafe.Pointer(&encodedArgs[0]))\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/language_client_go/baml_go/exports.go#L70-L106","documentation":"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.","triggerScenarios":"Any call through CallFunctionFromC, CallFunctionStreamFromC, CallFunctionParseFromC, BuildRequestFromC, or CancelFunctionCall where the returned C buffer does not decode as a cffi.InvocationResponse protobuf.","commonSituations":"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.","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"],"exampleFix":"// before\n// cached old .so downloaded months ago, mismatched with upgraded baml-go\n// after\n// rm -rf \"$(go env GOENV-cache-dir)/baml\" and rebuild so findOrDownloadLibrary fetches the matching library","handlingStrategy":"try-catch","validationCode":"libVer, err := baml.LoadedLibraryVersion()\n_ = libVer // compare against expected client version before making calls","typeGuard":null,"tryCatchPattern":"resp, err := baml.CallFunctionFromC(...)\nif err != nil && strings.Contains(err.Error(), \"failed to unmarshal FFI response\") {\n    // native/Go version skew: re-download matching library and retry init\n    return baml.Reinitialize()\n}","preventionTips":["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"],"tags":["protobuf","ffi","unmarshal"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}