BoundaryML/baml · error

unknown run error class

Error message

unknown run error class: {other}

What it means

run_error_class_from_proto (string-to-enum mapping) rejects any class string it does not recognize with InvalidData, listing the offending value. Known classes are runtime, host, panic, cancelled, internal; anything else (e.g. a new producer-side class or typo) fails the conversion.

Solutions

  1. Update the match arms in record.rs to handle the new class string
  2. Align producer to only emit the known class strings (lowercase, exact spelling)
  3. Normalize/whitelist class strings at the producer boundary before serialization
  4. Bump/sync the shared schema so both sides agree on the enum

Example fix

// before
match s.as_str() {
    "runtime" => ..., "internal" => ..., other => return Err(...)
}
// after
match s.as_str() {
    "runtime" => ..., "internal" => ..., "oom" => RunErrorClass::Oom, other => return Err(...)
}
Defensive patterns

Strategy: validation

Validate before calling

const KNOWN: &[&str] = &["runtime","host","panic","cancelled","internal"];
fn is_known_class(s: &str) -> bool { KNOWN.contains(&s) }

Try / catch

match convert_run_error(msg) {
    Ok(rec) => rec,
    Err(e) if e.to_string().starts_with("unknown run error class") => { log::warn!("{e}"); treat_as_internal(); },
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: TryFrom of a run-error record whose `class` string is not one of the five known variants — new enum values added upstream without updating this match, typos, or case mismatches ("Runtime" vs "runtime").

Common situations: Producer and consumer built from different schema versions where a new error class was added; hand-edited event payloads; localization/formatting of class strings before sending.

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

Appendix: source

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

        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,
    }
}

fn run_error_from_proto(value: crate::value::pb::RunErrorV1) -> io::Result<RunError> {
    Ok(RunError {
        class: match value.class.as_str() {
            "validation" => RunErrorClass::Validation,
            "runtime" => RunErrorClass::Runtime,
            "host" => RunErrorClass::Host,
            "panic" => RunErrorClass::Panic,
            "cancelled" => RunErrorClass::Cancelled,
            "internal" => RunErrorClass::Internal,
            other => {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    format!("unknown run error class: {other}"),
                ));
            }
        },
        message: value.message,
        details: value.details,
        value_ref: value.value_ref.map(ValueRef::try_from).transpose()?,
    })
}

fn run_error_to_proto(value: &RunError) -> crate::value::pb::RunErrorV1 {
    crate::value::pb::RunErrorV1 {
        class: match value.class {
            RunErrorClass::Validation => "validation",
            RunErrorClass::Runtime => "runtime",
            RunErrorClass::Host => "host",
            RunErrorClass::Panic => "panic",

View on GitHub (pinned to bd85ce9dee)