{"record":{"id":"f37f207ca87d5d83","repo":"BoundaryML/baml","slug":"expected-expected-got-actual","errorCode":null,"errorMessage":"Expected {expected}, got {actual}","messagePattern":"Expected (.+?), got (.+?)","errorType":"exception","errorClass":"LlmOpError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/sys_ops/src/sap.rs","lineNumber":52,"sourceCode":"    pub fn stream_ty_resolved(\n        &self,\n    ) -> Result<\n        sap_model::TyWithMeta<\n            sap_model::TyResolvedRef<'_, DefKey>,\n            &sap_model::TypeAnnotations<'_, DefKey>,\n        >,\n        &DefKey,\n    > {\n        self.db().resolve_with_meta(self.types.stream_ty().as_ref())\n    }\n}\n\n/// Errors that can occur during LLM operations. Relocated verbatim from\n/// `sys_llm`; only `ParseResponseError`, `JsonishError` and `SapError` are\n/// still constructible now that the SAP parse entry points are the sole users.\n#[derive(Debug, thiserror::Error)]\npub enum LlmOpError {\n    #[error(\"Expected {expected}, got {actual}\")]\n    TypeError {\n        expected: &'static str,\n        actual: String,\n    },\n\n    #[error(\"Parse response error: {0}\")]\n    ParseResponseError(String),\n\n    #[error(\"Jsonish error: {0}\")]\n    JsonishError(::bex_sap::jsonish::JsonishError),\n\n    #[error(\"SAP error: {0}\")]\n    SapError(::bex_sap::deserializer::coercer::ParsingError),\n}\n\nimpl From<LlmOpError> for ::sys_types::VmRustFnError {\n    fn from(e: LlmOpError) -> Self {\n        let baml: ::sys_types::VmBamlError = match e {","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/sys_ops/src/sap.rs#L34-L70","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet s = value.expect_string();\n// after\nlet s = match value { V::String(s) => s, V::Number(n) => n.to_string(), other => return Err(...) };","handlingStrategy":"try-catch","validationCode":"fn ensure_type(v: &Value, expected: &str) -> Result<(), String> {\n    match (expected, v) {\n        (\"string\", Value::String(_)) | (\"number\", Value::Number(_)) | (\"object\", Value::Object(_)) => Ok(()),\n        _ => Err(format!(\"expected {}, got {:?}\", expected, v)),\n    }\n}","typeGuard":"fn as_string(v: &Value) -> Option<&str> { if let Value::String(s) = v { Some(s) } else { None } }","tryCatchPattern":"match result {\n    Err(LlmOpError::TypeError { expected, actual }) => warn!(\"coerce {actual} to {expected}\"),\n    Err(e) => return Err(e),\n    Ok(v) => v,\n}","preventionTips":["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"],"tags":["llm","type-mismatch","parsing"],"backgroundTag":"type-mismatch","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}