BoundaryML/baml · error

nil success in InvocationResponse

Error message

nil success in InvocationResponse

What it means

After successfully unmarshaling an InvocationResponse, trigger_callback_object_handle expects the oneof response to carry a Success with a non-nil success payload. A Success case whose Success message pointer is nil violates the protocol contract, so the error is sent to the callback channel instead of a result.

Source

Thrown at engine/language_client_go/pkg/callbacks.go:242

func trigger_callback_object_handle(id uint32, callback CallbackData, content_bytes []byte) {
	var response cffi.InvocationResponse
	err := proto.Unmarshal(content_bytes, &response)
	if err != nil {
		safeSend(callback.channel, ResultCallback{Error: fmt.Errorf("failed to unmarshal InvocationResponse: %w", err)})
		safeClose(callback.channel)
		callbackMutex.Lock()
		defer callbackMutex.Unlock()
		deleteCallback(id)
		return
	}

	switch resp := response.GetResponse().(type) {
	case *cffi.InvocationResponse_Error:
		safeSend(callback.channel, ResultCallback{Error: BamlError{Message: resp.Error}})
	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)

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Upgrade the BAML runtime and Go bindings to matching latest versions — this indicates an internal invariant break.
  2. Reproduce with a minimal call (e.g. build_request_from_c) and file an issue with the call and versions.
  3. Ensure no custom patched native library is in use that could construct malformed responses.
  4. Handle the ResultCallback.Error path gracefully in your callback consumer so the failure is visible.

Example fix

// before
res := <-callbackCh // res.Error: nil success in InvocationResponse

// after
if res.Error != nil {
    log.Printf("baml callback failed: %v", res.Error) // surface and report with versions
    return res.Error
}
Defensive patterns

Strategy: try-catch

Try / catch

res := <-ch
if res.Error != nil {
	if strings.Contains(res.Error.Error(), "nil success in InvocationResponse") {
		log.Printf("baml internal protocol bug; versions: %s", baml.Version())
	}
	return res.Error
}

Prevention

When it happens

Trigger: The native side constructs an InvocationResponse with the Success case set but leaves the inner Success message nil — an internal bug in the Rust runtime, a protobuf default-construction mistake, or a wire round-trip that drops the nested message.

Common situations: Encountered during BAML internal protocol bugs or when a custom/patched runtime builds the response incorrectly; rarely caused by user code.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12). Data as JSON: /api/errors/d8fba833e733b6d7. Report an issue: GitHub.