{"record":{"id":"84e4553fc74e51bf","repo":"BoundaryML/baml","slug":"aborterror-detailed-message-stream","errorCode":null,"errorMessage":"AbortError: {detailed_message}","messagePattern":"AbortError: (.+?)","errorType":"exception","errorClass":"ExposedError::AbortError","httpStatus":null,"severity":"warning","filePath":"engine/baml-runtime/src/internal/llm_client/orchestrator/stream.rs","lineNumber":200,"sourceCode":"            as std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>,\n        None => Box::pin(futures::future::pending()),\n    };\n    tokio::pin!(cancel_future);\n\n    //advanced curl viewing, use render_raw_curl on each node. TODO\n    let total_nodes = iter.len();\n    for (node_index, node) in iter.into_iter().enumerate() {\n        let is_last_node = node_index == total_nodes - 1;\n        // Check for cancellation at the start of each iteration\n        let cancel_scope = node.scope.clone();\n        tokio::select! {\n            biased;\n\n            _ = &mut cancel_future => {\n                results.push((\n                    cancel_scope,\n                    LLMResponse::Cancelled(\"Operation cancelled\".to_string()),\n                    Some(Err(anyhow::anyhow!(\n                        crate::errors::ExposedError::AbortError {\n                            detailed_message: String::new()\n                        }\n                    ))),\n                ));\n                break;\n            }\n            result = async {\n                let prompt = match node.render_prompt(ir, prompt, ctx, params).await {\n                    Ok(p) => p,\n                    Err(e) => {\n                        return Some((\n                            node.scope,\n                            LLMResponse::InternalFailure(e.to_string()),\n                            Some(Err(anyhow::anyhow!(e.to_string()))),\n                        ));\n                    }\n                };","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-runtime/src/internal/llm_client/orchestrator/stream.rs#L182-L218","documentation":"BAML aborts an in-flight LLM stream when the caller cancels the operation (e.g. request dropped, deadline hit, or a client-side cancel token fires). The orchestrator's select loop breaks on the cancel future and records a Cancelled LLMResponse carrying an AbortError. It signals the work was stopped by the caller, not that the model or network failed.","triggerScenarios":"Calling a BAML function via orchestrate_stream (through run) and cancelling the future/request before the stream completes — HTTP client disconnects, tokio timeout, user aborts UI request, or explicit cancellation token triggered mid-stream.","commonSituations":"Web server clients closing the browser tab mid-generation; server frameworks dropping the request context; fetch/axios AbortController firing; gateway timeouts shorter than LLM generation time.","solutions":["Check upstream cancellation handling first — this is usually expected behavior, not a bug","Increase server/gateway timeouts (e.g. proxy read timeout) if long generations are killed prematurely","Ensure the client does not abort the fetch/request before consuming the full stream","Handle the Cancelled/AbortError case explicitly in your on_event/error callback instead of treating it as a model failure"],"exampleFix":"// before\nconst res = await b.functions.Extract(text); // client times out at 10s\n// after\nconst res = await b.functions.Extract(text, { tbConfig: { timeoutMs: 120000 } }); // align timeout with expected generation time","handlingStrategy":"try-catch","validationCode":"// Node: abort only when truly needed\nconst controller = new AbortController();\nsetTimeout(() => controller.abort(), 120000); // generous timeout > generation time","typeGuard":null,"tryCatchPattern":"try {\n  const res = await b.functions.Extract(input);\n} catch (e) {\n  if (e instanceof BamlAbortError || /AbortError|cancelled/i.test(String(e))) {\n    return; // expected cancellation, not a model failure\n  }\n  throw e;\n}","preventionTips":["Set timeouts longer than worst-case LLM generation","Don't abort requests on UI unmount unless the result is discarded intentionally","Log cancellations separately from real errors","Keep gateway/proxy read timeouts aligned with generation length"],"tags":["cancellation","streaming","abort"],"backgroundTag":"request-timeout","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"}