BoundaryML/baml · error

trace call process id must be 16 bytes, got {}

Error message

trace call process id must be 16 bytes, got {}

What it means

TraceCallKeyV1.process_id must be exactly 16 bytes (a 128-bit UUID-style identifier) to convert into the internal TraceCallKey's [u8; 16]. The TryFrom impl rejects any other length, including the length actually received, via InvalidData with this formatted message.

Source

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

    }
}

impl From<&BlobRef> for crate::value::pb::BlobRefV1 {
    fn from(value: &BlobRef) -> Self {
        Self {
            algorithm: value.algorithm.clone(),
            digest: value.digest.clone(),
            size_bytes: u64::try_from(value.size_bytes).unwrap_or(u64::MAX),
        }
    }
}

impl TryFrom<crate::value::pb::TraceCallKeyV1> for TraceCallKey {
    type Error = io::Error;

    fn try_from(value: crate::value::pb::TraceCallKeyV1) -> Result<Self, Self::Error> {
        let process_id: [u8; 16] = value.process_id.as_slice().try_into().map_err(|_| {
            io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "trace call process id must be 16 bytes, got {}",
                    value.process_id.len()
                ),
            )
        })?;
        Ok(Self {
            process_euid: ProcessEuid(process_id),
            engine_id: EngineId(value.engine_id),
            thread_id: BexThreadId(value.thread_id),
            call_id: BexCallId(value.call_id),
        })
    }
}

impl From<TraceCallKey> for crate::value::pb::TraceCallKeyV1 {
    fn from(value: TraceCallKey) -> Self {

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Fix the producer to always emit a 16-byte process_id (e.g. a UUID v4 as raw bytes)
  2. Pad/truncate or regenerate IDs in a migration tool when converting legacy streams
  3. Validate process_id.len() == 16 at the writer boundary before serializing
  4. Inspect the reported length in the message to identify which producer/version wrote the bad ID

Example fix

// before
let process_id = value.process_id; // arbitrary-length Vec<u8>
// after
let mut process_id = [0u8; 16];
if value.process_id.len() == 16 { process_id.copy_from_slice(&value.process_id); } else { return Err(...); }
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Try / catch

TraceCallKey::try_from(raw).map_err(|e| { warn!("bad process id: {e}"); CorruptionKind::BadProcessId.into() })

Prevention

When it happens

Trigger: Decoding a TraceCallKeyV1 whose process_id field is empty, truncated by corruption, or written with a different-length ID (e.g. 8-byte, 32-byte hex string) by an incompatible producer.

Common situations: Version skew where an older/newer writer uses a different process-id representation, manual proto construction with placeholder IDs, or byte-level file corruption.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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