{"record":{"id":"d15d8c1821b60649","repo":"BoundaryML/baml","slug":"sap-error-0","errorCode":null,"errorMessage":"SAP error: {0}","messagePattern":"SAP error: (.+?)","errorType":"exception","errorClass":"LlmOpError","httpStatus":null,"severity":"error","filePath":"baml_language/crates/sys_ops/src/sap.rs","lineNumber":64,"sourceCode":"\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 {\n            LlmOpError::TypeError { expected, actual } => {\n                ::sys_types::VmBamlError::InvalidArgument {\n                    message: format!(\"expected {expected}, got {actual}\"),\n                }\n            }\n            LlmOpError::ParseResponseError(e) => ::sys_types::VmBamlError::LlmClient { message: e },\n            LlmOpError::JsonishError(e) => ::sys_types::VmBamlError::LlmClient {\n                message: e.to_string(),\n            },\n            LlmOpError::SapError(e) => ::sys_types::VmBamlError::LlmClient {\n                message: e.to_string(),\n            },","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/baml_language/crates/sys_ops/src/sap.rs#L46-L82","documentation":"LlmOpError::SapError wraps a bex_sap::deserializer::coercer::ParsingError from the SAP deserializer coercer — the stage that coerces a parsed JSON-ish value into the target schema type. It indicates the value exists but cannot be coerced to the required shape.","triggerScenarios":"The coercer fails while deserializing a jsonish value into the expected output class (missing required field, uncoercible value, wrong field types); the error is wrapped as SapError and later converted to a VmRustFnError/VmBamlError.","commonSituations":"Model omits a required field or invents extra ones; values are close-but-wrong types the coercer won't cast; schema changed after the prompt was written.","solutions":["Read the wrapped ParsingError to find the failing field/coercion","Align the prompt's output schema with the expected BAML class exactly","Make the schema fields optional where the model legitimately may omit them","Retry the generation if the omission looks stochastic"],"exampleFix":"// before\nclass Result { score int }\n// after\nclass Result { score int? }","handlingStrategy":"try-catch","validationCode":"fn has_required_fields(v: &serde_json::Value, required: &[&str]) -> bool {\n    required.iter().all(|k| v.get(k).is_some())\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(LlmOpError::SapError(pe)) => { eprintln!(\"coercion failed at {:?}\", pe); adjust_prompt_and_retry() }\n    other => other,\n}","preventionTips":["Keep the prompt's documented schema exactly in sync with the BAML class","Mark fields optional when the model may omit them","Sample a few generations in tests to catch flaky field omissions"],"tags":["llm","deserialization","coercion","sap"],"backgroundTag":"schema-validation-failed","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}