{"record":{"id":"686b8de17e9a39b2","repo":"BoundaryML/baml","slug":"value-was-marked-done-but-was-incomplete-in-the-stream","errorCode":null,"errorMessage":"Value was marked Done, but was incomplete in the stream","messagePattern":"Value was marked Done, but was incomplete in the stream","errorType":"exception","errorClass":"StreamingError","httpStatus":null,"severity":"error","filePath":"engine/baml-lib/jsonish/src/deserializer/semantic_streaming.rs","lineNumber":24,"sourceCode":"use anyhow::{Context, Error};\nuse baml_types::{\n    BamlMap, BamlValueWithMeta, Completion, CompletionState, ResponseCheck, TypeIR, TypeValue,\n};\nuse indexmap::{IndexMap, IndexSet};\nuse internal_baml_core::ir::{\n    ir_helpers::infer_type_with_meta,\n    repr::{IntermediateRepr, Walker},\n    Field, IRHelper, IRHelperExtended, IRSemanticStreamingHelper,\n};\nuse thiserror;\n\nuse crate::{deserializer::coercer::ParsingError, BamlValueWithFlags, Flag};\n\n#[derive(Debug, thiserror::Error)]\npub enum StreamingError {\n    #[error(\"Expected to encounter a class\")]\n    ExpectedClass,\n    #[error(\"Value was marked Done, but was incomplete in the stream\")]\n    IncompleteDoneValue,\n    #[error(\"Class instance did not contain fields marked as needed: {fields:?}\")]\n    MissingNeededFields { fields: Vec<String> },\n    #[error(\"Failed to distribute_type_with_meta: {0}\")]\n    DistributeTypeWithMetaFailure(#[from] anyhow::Error),\n}\n\n/// For a given baml value, traverse its nodes, comparing the completion state\n/// of each node against the streaming behavior of the node's type.\npub fn validate_streaming_state(\n    ir: &impl IRHelperExtended,\n    baml_value: &BamlValueWithFlags,\n    mode: baml_types::StreamingMode,\n) -> Result<BamlValueWithMeta<Completion>, StreamingError> {\n    let baml_value_with_meta_flags: BamlValueWithMeta<Vec<Flag>> = baml_value.clone().into();\n    let typed_baml_value: BamlValueWithMeta<(Vec<Flag>, TypeIR)> =\n        ir.distribute_type_with_meta(baml_value_with_meta_flags, baml_value.field_type().clone())?;\n    let baml_value_with_streaming_state_and_behavior =","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-lib/jsonish/src/deserializer/semantic_streaming.rs#L6-L42","documentation":"StreamingError::IncompleteDoneValue indicates a value in the stream was marked Done (complete) but its content is not actually parseable as a complete value. The streaming state machine's Done marker disagrees with the actual data, so validation fails rather than silently returning truncated output.","triggerScenarios":"validate_streaming_state traverses nodes and finds one whose completion state is Done while its parsed value is still incomplete — e.g. the stream terminated mid-object after the parser optimistically marked it done, or truncated JSON that matched a done heuristic.","commonSituations":"LLM hit max_tokens mid-JSON; network/proxy cut the stream; stop-sequences fired early; parser heuristics marking partial braces as complete in very long outputs.","solutions":["Re-run the request with a higher max_tokens / output budget.","Enable partial streaming parsing and validate completeness before treating the value as final.","Check stop sequences and provider settings that may terminate generation early.","Retry the request; if reproducible, inspect whether your proxy/client truncates streams."],"exampleFix":"// before: treating final chunk as complete\nlet value = parse_done(chunk)?;\n// after: guard\nmatch validate_streaming_state(&value) {\n    Err(StreamingError::IncompleteDoneValue) => retry_or_request_continuation(),\n    other => other?,\n}","handlingStrategy":"retry","validationCode":"// before trusting a Done value\nif let Err(StreamingError::IncompleteDoneValue) = validate_streaming_state(&value) {\n    // do not use the value; request continuation or retry\n}","typeGuard":"fn is_complete(value: &BamlValueWithFlags) -> bool {\n    validate_streaming_state(value).is_ok()\n}","tryCatchPattern":"match validate_streaming_state(&value) {\n    Err(StreamingError::IncompleteDoneValue) => retry_with_higher_budget().await?,\n    Err(e) => return Err(e.into()),\n    Ok(()) => commit(value),\n}","preventionTips":["Set generous max_tokens budgets for structured output","Avoid aggressive stop sequences that cut JSON mid-object","Check proxy/client stream handling for truncation","Retry transient truncations automatically"],"tags":["rust","streaming","truncated-output"],"backgroundTag":"invalid-json-response","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}