BoundaryML/baml · error

Expected Collector, got {}

Error message

Expected Collector, got {}

What it means

Thrown while decoding BamlFunctionArguments: the host passes a list of raw pointer objects expected to all be Collectors, but RawPtrType::decode resolved one of them to a different pointer type (the message includes the actual type name). This is a defensive check that the FFI object registry returns the right variant.

Source

Thrown at engine/language_client_cffi/src/ctypes/function_args_decode.rs:44

            .kwargs
            .into_iter()
            .map(from_host_kv_to_baml_kv)
            .collect::<Result<_, _>>()?;
        let client_registry = from
            .client_registry
            .map(ClientRegistry::decode)
            .transpose()?
            .filter(|r| !r.is_empty());
        let env_vars = from.env.into_iter().map(|e| (e.key, e.value)).collect();
        let collectors = {
            let collectors = from
                .collectors
                .into_iter()
                .map(RawPtrType::decode)
                .map(|r| match r {
                    Ok(RawPtrType::Collector(c)) => Ok(c),
                    Err(e) => Err(e),
                    Ok(other) => Err(anyhow::anyhow!("Expected Collector, got {}", other.name())),
                })
                .collect::<Result<Vec<_>, _>>()?;
            if collectors.is_empty() {
                None
            } else {
                Some(collectors)
            }
        };
        let type_builder = from
            .type_builder
            .map(RawPtrType::decode)
            .transpose()?
            .map(|r| match r {
                RawPtrType::TypeBuilder(t) => Ok(t),
                other => Err(anyhow::anyhow!(
                    "Expected TypeBuilder, got {}",
                    other.name()
                )),

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Verify that the object you pass in the collectors argument is actually a Collector instance created via the BAML client's collector API
  2. Recreate the object if its handle may be stale, and avoid reusing pointer IDs across calls
  3. Align host SDK and engine versions so RawPtrType tags match what the decoder expects

Example fix

// before (host pseudocode)
args.collectors = [type_builder]  // wrong object

// after
args.collectors = [baml_collector]  // actual Collector instance
Defensive patterns

Strategy: type-guard

Validate before calling

# host side
for c in collectors:
    if not isinstance(c, Collector):
        raise TypeError(f"collectors must contain Collector instances, got {type(c).__name__}")

Type guard

function isCollector(obj) { return obj && obj.__baml_type === 'Collector'; }
const safeCollectors = maybeCollectors.filter(isCollector);

Try / catch

try:
    result = client.CallFunction(fn, args)
except Exception as e:
    if "Expected Collector" in str(e):
        raise TypeError("Pass only Collector objects in the collectors argument") from e
    raise

Prevention

When it happens

Trigger: Passing a non-Collector object (e.g. a TypeBuilder or runtime/client pointer) inside the collectors list of a function call's arguments.

Common situations: Mixing up object references in host code (passing the wrong handle/variable into a b.collectors-style argument), stale or recycled pointer IDs from the object registry, or version skew where pointer type tags shifted.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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