BoundaryML/baml · error
unexpected response type in InvocationResponse
Error message
unexpected response type in InvocationResponse
What it means
The outer switch on InvocationResponse.GetResponse() expects either an Error or a Success case. Any other (or unset) oneof state falls to the default branch and produces this error, meaning the response message arrived without a valid response variant.
Source
Thrown at engine/language_client_go/pkg/callbacks.go:257
case *cffi.InvocationResponse_Success:
success := resp.Success
if success == nil {
safeSend(callback.channel, ResultCallback{Error: fmt.Errorf("nil success in InvocationResponse")})
} else {
switch result := success.GetResult().(type) {
case *cffi.InvocationResponseSuccess_Object:
decoded, decodeErr := decodeRawObjectImpl(callback.runtime, result.Object)
if decodeErr != nil {
safeSend(callback.channel, ResultCallback{Error: fmt.Errorf("failed to decode object handle: %w", decodeErr)})
} else {
safeSend(callback.channel, ResultCallback{HasData: true, Data: decoded})
}
default:
safeSend(callback.channel, ResultCallback{Error: fmt.Errorf("unexpected result type in InvocationResponse: %T", success.GetResult())})
}
}
default:
safeSend(callback.channel, ResultCallback{Error: fmt.Errorf("unexpected response type in InvocationResponse")})
}
safeClose(callback.channel)
callbackMutex.Lock()
defer callbackMutex.Unlock()
deleteCallback(id)
}
func create_unique_id(ctx context.Context, onTick OnTickCallbackData) (uint32, chan ResultCallback) {
id := nextCallbackID.Add(1)
callbackMutex.Lock()
defer callbackMutex.Unlock()
dynamicCallbacks[id] = CallbackData{channel: make(chan ResultCallback, 64), ctx: ctx, onTick: onTick, responseType: responseTypeValue}
callbackLog("[CLIENT_GO_CALLBACK_ADD] id=%d map_size=%d", id, len(dynamicCallbacks))
return id, dynamicCallbacks[id].channel
}
// create_unique_id_for_object creates a callback ID for object-handle responses (e.g. build_request).View on GitHub (pinned to bd85ce9dee)
Solutions
- Upgrade and align BAML Go bindings and native runtime versions.
- Check native runtime logs for an internal failure preceding the callback.
- Retry the operation once to rule out a transient empty-response race.
- Report with versions and a minimal reproduction if persistent.
Example fix
// before
res := <-callbackCh // Error: unexpected response type in InvocationResponse
// after
if res.Error != nil {
if strings.Contains(res.Error.Error(), "unexpected response type") {
log.Printf("baml protocol error, check version alignment: %v", res.Error)
}
return res.Error
} Defensive patterns
Strategy: retry
Try / catch
for attempt := 0; attempt < 2; attempt++ {
res := <-ch
if res.Error == nil {
return res.Data, nil
}
if !strings.Contains(res.Error.Error(), "unexpected response type in InvocationResponse") || attempt == 1 {
return nil, res.Error
}
// empty/invalid oneof: retry once for transient empty response
} Prevention
- Keep versions aligned between bindings and runtime
- Check native runtime logs for precursor internal errors
- Add a single retry for empty-response races
When it happens
Trigger: The native side returns an InvocationResponse with neither Error nor Success set — typically a zero-value/empty protobuf response due to an internal failure before response construction, or a protocol version mismatch that drops the oneof field.
Common situations: Native runtime crash or early-return path that emits an empty response; mismatched Go bindings vs native library; corrupted callback payload that partially decodes.
Related errors
- failed to unmarshal content bytes: %w
- destructor returned unexpected result: %v
- failed to marshal object method arguments: %w
- failed to unmarshal InvocationResponse: %w
- nil success in InvocationResponse
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/735030ab9a805993.
Report an issue: GitHub.