BoundaryML/baml · error

unexpected type for usage: %T

Error message

unexpected type for usage: %T

What it means

After Collector.Usage() successfully calls the runtime's `usage` method, it asserts the decoded result implements the Usage interface. If the FFI layer returns any other Go type, this error is thrown. The method call itself succeeded, but the returned payload did not match the documented Usage shape — a contract violation between the native runtime and the Go bindings.

Source

Thrown at engine/language_client_go/pkg/rawobjects_collector.go:35

}

func (c *collector) ObjectType() cffi.BamlObjectType {
	return cffi.BamlObjectType_OBJECT_COLLECTOR
}

func (c *collector) pointer() int64 {
	return c.RawObject.Pointer()
}

func (c *collector) Usage() (Usage, error) {
	result, err := raw_objects.CallMethod(c, "usage", nil)
	if err != nil {
		return nil, fmt.Errorf("failed to get usage: %w", err)
	}

	usage, ok := result.(Usage)
	if !ok {
		return nil, fmt.Errorf("unexpected type for usage: %T", result)
	}

	return usage, nil
}

func (c *collector) Name() (string, error) {
	result, err := raw_objects.CallMethod(c, "name", nil)
	if err != nil {
		return "", fmt.Errorf("failed to get name: %w", err)
	}

	name, ok := result.(string)
	if !ok {
		return "", fmt.Errorf("unexpected type for name: %T", result)
	}

	return name, nil
}

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Match Go binding and BAML runtime versions exactly; upgrade/reinstall both together.
  2. Check whether the underlying collector still tracks active calls; a usage object may only exist after at least one tracked call.
  3. Recreate the collector and retry to rule out corrupt runtime state.
  4. Report the printed %T type to BAML maintainers if it reproduces on matched versions.

Example fix

// before
usage, err := collector.Usage()
if err != nil { panic(err) }
// after
usage, err := collector.Usage()
if err != nil {
    return nil, fmt.Errorf("usage shape unexpected, verify baml version parity: %w", err)
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Only call Usage after at least one tracked call:
// if callCount == 0 { return nil, errors.New("no tracked calls yet") }

Type guard

func isUsage(result any) bool {
    _, ok := result.(Usage)
    return ok
}

Try / catch

usage, err := collector.Usage()
if err != nil {
    if strings.Contains(err.Error(), "unexpected type for usage") {
        return nil, fmt.Errorf("usage payload shape violated (check version parity): %w", err)
    }
    return nil, err
}

Prevention

When it happens

Trigger: Calling collector.Usage() when the runtime returns a non-Usage value: a raw pointer typed as a different object, nil from a degraded runtime response, or a result decoded with the wrong object type tag.

Common situations: Version drift between the Go module and the native BAML runtime changing the usage object's type tag; runtime-side partial failure producing a placeholder object; a collector created by a different runtime instance.

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