BoundaryML/baml · critical

object constructor returned nil pointer

Error message

object constructor returned nil pointer

What it means

NewRawObject checks the buffer returned by the native constructor call; if its length is nonzero but the pointer is nil, it reports that the object constructor returned a nil pointer. This is a defensive invariant check against the CFFI boundary — a non-empty claimed length with no backing memory. It indicates a broken or corrupted response from the native runtime.

Source

Thrown at engine/language_client_go/baml_go/raw_objects/utils.go:127

		Kwargs: kwargs,
	}

	encodedArgs, err := proto.Marshal(&args)
	if err != nil {
		return nil, fmt.Errorf("failed to marshal object constructor arguments: %w", err)
	}
	cEncodedArgs := (*C.char)(unsafe.Pointer(&encodedArgs[0]))

	cBuf := C.WrapCallObjectConstructor(cEncodedArgs, C.uintptr_t(len(encodedArgs)))

	content_bytes := C.GoBytes(unsafe.Pointer(cBuf.ptr), C.int32_t(cBuf.len))
	C.WrapFreeBuffer(cBuf) // Free the buffer after use

	if cBuf.len == 0 {
		return nil, fmt.Errorf("failed to call object constructor")
	}
	if cBuf.ptr == nil {
		return nil, fmt.Errorf("object constructor returned nil pointer")
	}

	var content_holder cffi.InvocationResponse
	err = proto.Unmarshal(content_bytes, &content_holder)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal content bytes: %w", err)
	}
	parsed, err := decodeObjectResponse(rt, &content_holder)
	if err != nil {
		return nil, fmt.Errorf("failed to decode object response: %w", err)
	}

	return parsed, nil
}

func destructor(object RawPointer) error {
	result, err := CallMethod(object, "~destructor", nil)

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Upgrade the baml Go module so the CFFI wrappers and native library come from the same release, then clean-rebuild (go clean -cache).
  2. Capture the exact object type and kwargs and file a bug with the BAML maintainers — this check guards against an internal invariant violation.
  3. Rule out memory corruption in your own process: check for cgo misuse, unsafe casts, or concurrent calls into the runtime during init.
  4. Test with a different platform/arch build of the native library to exclude a broken artifact.

Example fix

// before
// treating the empty/nil buffer as usable
obj, err := NewRawObject(ctx, objectType, kwargs)
// err: object constructor returned nil pointer

// after
// pin matching versions and rebuild natively
// go.mod: require github.com/boundaryml/baml v0.XX.0
// $ go clean -cache && go mod download && go build
// if it persists, file a bug with the repro args
Defensive patterns

Strategy: try-catch

Validate before calling

// No caller-side pre-check exists; guard versions instead:
// go.mod pins baml module == native library release
require github.com/boundaryml/baml v0.XX.0

Type guard

func responseUsable(ptr unsafe.Pointer, length int) bool {
    return ptr != nil && length > 0
}

Try / catch

obj, err := NewRawObject(ctx, objectType, kwargs)
if err != nil && strings.Contains(err.Error(), "nil pointer") {
    log.Printf("BAML FFI invariant violation; rebuild with matching versions and report bug")
    return err
}

Prevention

When it happens

Trigger: WrapCallObjectConstructor returning a cBuf with len > 0 but ptr == nil during NewRawObject (or its callers NewCollector, newMediaFromUrl, newMediaFromBase64, NewTypeBuilder). Practically only occurs with a malfunctioning/mismatched native runtime or memory corruption at the FFI boundary.

Common situations: Mixed versions of generated CFFI bindings and the native library; a buggy native build; unsafe memory reuse bugs surfacing as corrupted buffers. Extremely rare in normal usage.

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/75a226060d1ec326. Report an issue: GitHub.