BoundaryML/baml · error

boundary id must be 16 bytes, got

Error message

boundary id must be 16 bytes, got {}

What it means

boundary_id_from_slice requires the input byte slice to be exactly 16 bytes to build a BoundaryId (a 128-bit identifier, likely a UUID). Any other length is rejected with io::ErrorKind::InvalidData and the actual length in the message.

Solutions

  1. Ensure the producer always writes exactly 16 bytes (e.g. uuid::Uuid::as_bytes()) for boundary ids
  2. Check for schema/version drift where id size changed between producer and consumer
  3. Validate the byte length before calling try_into and surface a clearer upstream error
  4. Regenerate/repair affected event records with correctly sized ids

Example fix

// before
let id = boundary_id_from_slice(&bytes)?; // bytes.len() == 32
// after
let uuid = uuid::Uuid::new_v4();
let id = boundary_id_from_slice(uuid.as_bytes())?; // always 16 bytes
Defensive patterns

Strategy: validation

Validate before calling

fn is_boundary_id(bytes: &[u8]) -> bool { bytes.len() == 16 }

Type guard

fn as_boundary_id(bytes: &[u8]) -> Option<[u8; 16]> { bytes.try_into().ok() }

Try / catch

match boundary_id_from_slice(&bytes) {
    Ok(id) => id,
    Err(e) if e.kind() == io::ErrorKind::InvalidData => { log::warn!("bad boundary id length: {e}"); skip_record(); },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Converting a Vec<u8>/byte slice from protobuf bytes fields into BoundaryId where the producer wrote a truncated, zero-length, or otherwise non-16-byte buffer.

Common situations: Older producer versions writing 8- or 32-byte ids; empty bytes field defaulting to empty vec in proto3; manual id generation not using 16-byte UUIDs.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at baml_language/crates/bex_events/src/value/record.rs:567

                helper: helper.clone(),
            }),
            RunTarget::Companion {
                parent_boundary_id,
                function_name,
            } => Target::Companion(crate::value::pb::CompanionRunTargetV1 {
                parent_boundary_id: parent_boundary_id.map(|id| id.as_bytes().to_vec()),
                function_name: function_name.clone(),
            }),
            RunTarget::Internal { name } => {
                Target::Internal(crate::value::pb::InternalRunTargetV1 { name: name.clone() })
            }
        }),
    }
}

fn boundary_id_from_slice(value: &[u8]) -> io::Result<BoundaryId> {
    let bytes: [u8; 16] = value.try_into().map_err(|_| {
        io::Error::new(
            io::ErrorKind::InvalidData,
            format!("boundary id must be 16 bytes, got {}", value.len()),
        )
    })?;
    Ok(BoundaryId::from_bytes(bytes))
}

fn run_status_to_proto(status: RunStatus) -> crate::value::pb::RunStatus {
    match status {
        RunStatus::Pending => crate::value::pb::RunStatus::Pending,
        RunStatus::Running => crate::value::pb::RunStatus::Running,
        RunStatus::WaitingForInput => crate::value::pb::RunStatus::WaitingForInput,
        RunStatus::WaitingForEnv => crate::value::pb::RunStatus::WaitingForEnv,
        RunStatus::Cancelling => crate::value::pb::RunStatus::Cancelling,
        RunStatus::Succeeded => crate::value::pb::RunStatus::Succeeded,
        RunStatus::Failed => crate::value::pb::RunStatus::Failed,
        RunStatus::Cancelled => crate::value::pb::RunStatus::Cancelled,
        RunStatus::Panicked => crate::value::pb::RunStatus::Panicked,

View on GitHub (pinned to bd85ce9dee)