BoundaryML/baml · error · LlmOpError
Expected {expected}, got {actual}
Error message
Expected {expected}, got {actual} What it means
LlmOpError::TypeError from the SAP LLM operation layer: a value received during an LLM operation did not have the expected Rust type. It is constructed by the SAP parse entry points when internal type expectations about response data are violated.
Source
Thrown at baml_language/crates/sys_ops/src/sap.rs:52
pub fn stream_ty_resolved(
&self,
) -> Result<
sap_model::TyWithMeta<
sap_model::TyResolvedRef<'_, DefKey>,
&sap_model::TypeAnnotations<'_, DefKey>,
>,
&DefKey,
> {
self.db().resolve_with_meta(self.types.stream_ty().as_ref())
}
}
/// Errors that can occur during LLM operations. Relocated verbatim from
/// `sys_llm`; only `ParseResponseError`, `JsonishError` and `SapError` are
/// still constructible now that the SAP parse entry points are the sole users.
#[derive(Debug, thiserror::Error)]
pub enum LlmOpError {
#[error("Expected {expected}, got {actual}")]
TypeError {
expected: &'static str,
actual: String,
},
#[error("Parse response error: {0}")]
ParseResponseError(String),
#[error("Jsonish error: {0}")]
JsonishError(::bex_sap::jsonish::JsonishError),
#[error("SAP error: {0}")]
SapError(::bex_sap::deserializer::coercer::ParsingError),
}
impl From<LlmOpError> for ::sys_types::VmRustFnError {
fn from(e: LlmOpError) -> Self {
let baml: ::sys_types::VmBamlError = match e {View on GitHub (pinned to bd85ce9dee)
Solutions
- Validate/repair the LLM response JSON against the expected schema before parsing
- Add or fix coercion so the unexpected type is converted (e.g. number to string)
- Check for model or prompt changes causing the shifted response shape and update the expected type
Example fix
// before
let s = value.expect_string();
// after
let s = match value { V::String(s) => s, V::Number(n) => n.to_string(), other => return Err(...) }; Defensive patterns
Strategy: try-catch
Validate before calling
fn ensure_type(v: &Value, expected: &str) -> Result<(), String> {
match (expected, v) {
("string", Value::String(_)) | ("number", Value::Number(_)) | ("object", Value::Object(_)) => Ok(()),
_ => Err(format!("expected {}, got {:?}", expected, v)),
}
} Type guard
fn as_string(v: &Value) -> Option<&str> { if let Value::String(s) = v { Some(s) } else { None } } Try / catch
match result {
Err(LlmOpError::TypeError { expected, actual }) => warn!("coerce {actual} to {expected}"),
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Validate LLM JSON against the schema before parsing
- Add coercions for common type drifts (number-as-string)
- Pin model versions to reduce response-shape drift
When it happens
Trigger: A SAP parse entry point (sole remaining constructor of LlmOpError variants) encounters a value whose type doesn't match the statically expected 'expected' kind — e.g. expecting a string field but finding a number/object in the model response payload.
Common situations: LLM returning malformed or differently-typed JSON than the schema expects; drifting API response shapes after model changes; version changes in the SAP/jsonish layer.
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
- Parse response error: {0}
- Jsonish error: {0}
- error parsing function result: {e}
- failing inside parsed_using_types: {e:?}
- error while parsing LLM response for function {function_name
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/f37f207ca87d5d83.
Report an issue: GitHub.