BoundaryML/baml · error

capture loss omitted kind

Error message

capture loss omitted kind

What it means

CaptureLossV1 records that telemetry was dropped (e.g. a queue overflow); its 'kind' enum must be explicitly set (currently Log). When kind() returns Unspecified — the proto3 default for an unset enum — the TryFrom conversion rejects the record with InvalidData and this message, since a loss record without a kind is meaningless.

Source

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

    fn from(value: &LogEventRecord) -> Self {
        Self {
            call: Some(value.call.into()),
            level: value.level.clone(),
            source: value.source.as_ref().map(Into::into),
            timestamp_ms: value.timestamp_ms,
            message_preview: value.message_preview.clone(),
        }
    }
}

impl TryFrom<crate::value::pb::CaptureLossV1> for CaptureLossRecord {
    type Error = io::Error;

    fn try_from(value: crate::value::pb::CaptureLossV1) -> Result<Self, Self::Error> {
        let kind = match value.kind() {
            crate::value::pb::CaptureLossKind::Log => CaptureLossKind::Log,
            crate::value::pb::CaptureLossKind::Unspecified => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "capture loss omitted kind",
                ));
            }
        };
        let reason = match value.reason() {
            crate::value::pb::CaptureLossReason::QueueFull => CaptureLossReason::QueueFull,
            crate::value::pb::CaptureLossReason::Unspecified => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    "capture loss omitted reason",
                ));
            }
        };
        Ok(Self {
            kind,
            reason,
            skipped_count: value.skipped_count,

View on GitHub (pinned to bd85ce9dee)

Solutions

  1. Fix the producer to set kind = CaptureLossKind::Log (or the appropriate kind) on every loss record
  2. Set the enum explicitly when constructing the proto manually (avoid ..Default::default() for enum fields)
  3. Default Unspecified to Log at decode time if your data contract guarantees only log-loss records exist
  4. Check writer/reader version skew and migrate legacy streams

Example fix

// before
let loss = pb::CaptureLossV1 { reason: ..., ..Default::default() };
// after
let loss = pb::CaptureLossV1 { kind: pb::CaptureLossKind::Log as i32, reason: ..., ..Default::default() };
Defensive patterns

Strategy: validation

Validate before calling

fn loss_kind_set(loss: &pb::CaptureLossV1) -> bool { loss.kind() != pb::CaptureLossKind::Unspecified }

Type guard

fn valid_loss_kind(loss: &pb::CaptureLossV1) -> bool { matches!(loss.kind(), pb::CaptureLossKind::Log) }

Try / catch

CaptureLossRecord::try_from(loss).map_err(|e| if e.to_string().contains("omitted kind") { default_kind_record(loss) } else { e })

Prevention

When it happens

Trigger: Decoding a CaptureLossV1 whose kind field was never set by the writer, or was reset when the message was copied/rebuilt by intermediate code.

Common situations: Older writers predating the kind field, hand-built loss records in tests/tools, migration code that reconstructs the proto without copying enum fields.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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