{"record":{"id":"900827775f8a10a3","repo":"Hmbown/CodeWhale","slug":"antigravity-cloud-code-stream-ended-without-a-text","errorCode":null,"errorMessage":"Antigravity cloud-code stream ended without a text part","messagePattern":"Antigravity cloud-code stream ended without a text part","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/client/cloud_code.rs","lineNumber":271,"sourceCode":"                        });\n                        yield Ok(StreamEvent::ContentBlockStart {\n                            index: 0,\n                            content_block: ContentBlockStart::Text {\n                                text: String::new(),\n                            },\n                        });\n                    }\n                    yield Ok(StreamEvent::ContentBlockDelta {\n                        index: 0,\n                        delta: Delta::TextDelta { text },\n                    });\n                }\n            }\n            if started {\n                yield Ok(StreamEvent::ContentBlockStop { index: 0 });\n                yield Ok(StreamEvent::MessageStop);\n            } else {\n                yield Err(anyhow::anyhow!(\n                    \"Antigravity cloud-code stream ended without a text part\"\n                ));\n            }\n        };\n        Ok(Box::pin(stream))\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::models::{Message, MessageRequest, SystemBlock, SystemPrompt};\n\n    fn text_request(model: &str, prompt: &str) -> MessageRequest {\n        MessageRequest {\n            model: model.to_string(),\n            messages: vec![Message {\n                role: \"user\".to_string(),","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/client/cloud_code.rs#L253-L289","documentation":"The Antigravity cloud-code stream finished (EOF or `[DONE]`) but no text part was ever extracted — `started` stayed false, so no MessageStart was emitted. The client yields this error instead of fabricating an empty assistant message, so callers cannot mistake an empty completion for a successful one.","triggerScenarios":"The provider returned only non-text frames (thought/usage/metadata events, empty candidates) for the whole turn; a transient empty completion; the model produced a response whose parts the extractor does not recognize.","commonSituations":"Very short or refused completions; route hiccups returning wrapper frames with no content; prompts that elicit tool-only or empty responses.","solutions":["Retry the request — empty completions are typically transient","If deterministic, simplify the prompt to check whether the route produces any text","Capture the raw frames and report them so the extractor can be extended if a real text part went unmapped"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_empty_cloud_code_stream(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"ended without a text part\")\n}","tryCatchPattern":"match stream.next().await {\n    Some(Err(e)) if is_empty_cloud_code_stream(&e) => {\n        backoff_retry().await; // empty completions are usually transient\n    }\n    Some(Err(e)) => return Err(e),\n    other => { /* forward */ }\n}","preventionTips":["Retry empty completions once before treating them as a route failure","Do not accept an empty assistant turn as success — the guard exists to prevent that","Capture raw frames if a route is deterministically textless, and report them"],"tags":["antigravity","cloud-code","empty-response","streaming"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}