Hmbown/CodeWhale · error

expected text

Error message

expected text

What it means

Test panic asserting that the first content block of the synthesized response is a Text block. MockLlmClient::create_message synthesizes a response from a canned simple_text_turn when no message is queued; the test matches on resp.content[0] and panics if the block is not ContentBlock::Text.

Solutions

  1. Print resp.content before matching to see what block type is actually first.
  2. Fix the synthesis path so simple_text_turn produces ContentBlock::Text as the first block.
  3. If the response legitimately starts with another block type, update the test to find the text block instead of assuming index 0.

Example fix

// before
let text = match &resp.content[0] { ContentBlock::Text { text, .. } => text.clone(), _ => panic!("expected text") };
// after
let text = resp.content.iter().find_map(|b| if let ContentBlock::Text { text, .. } = b { Some(text.clone()) } else { None }).expect("expected text block in response");
Defensive patterns

Strategy: type-guard

Validate before calling

// verify the canned turn produces a text block before asserting
let resp = mock.create_message(req).await.unwrap();
assert!(!resp.content.is_empty(), "synthesized response has no content blocks");

Type guard

fn first_text<'a>(blocks: &'a [ContentBlock]) -> Option<&'a str> { blocks.iter().find_map(|b| if let ContentBlock::Text { text, .. } = b { Some(text.as_str()) } else { None }) }

Try / catch

let text = first_text(&resp.content).expect("expected text block").to_string();

Prevention

When it happens

Trigger: Calling create_message on a mock seeded with canned::simple_text_turn("synthesized") when resp.content[0] holds a non-text ContentBlock (tool_use, thinking, etc.).

Common situations: A change to the streaming-turn synthesis ordering or ContentBlock construction inserted a non-text block first; block indexing changed.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/15f1e4f4edd33a34. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/llm_client/mock.rs:599

            }],
            model: "mock-model".to_string(),
            stop_reason: Some("end_turn".to_string()),
            stop_sequence: None,
            container: None,
            usage: Usage::default(),
        });

        let resp = mock.create_message(empty_request()).await.unwrap();
        assert_eq!(resp.id, "preset");
    }

    #[tokio::test]
    async fn create_message_synthesizes_from_streaming_turn_when_no_message_queued() {
        let mock = MockLlmClient::new(vec![canned::simple_text_turn("synthesized")]);
        let resp = mock.create_message(empty_request()).await.unwrap();
        let text = match &resp.content[0] {
            ContentBlock::Text { text, .. } => text.clone(),
            _ => panic!("expected text"),
        };
        assert_eq!(text, "synthesized");
        assert_eq!(resp.stop_reason.as_deref(), Some("end_turn"));
    }

    #[tokio::test]
    async fn create_message_synthesizes_from_factory_turn() {
        let mock = MockLlmClient::new(Vec::new());
        mock.push_factory(|request| {
            assert_eq!(request.model, "mock-model");
            canned::simple_text_turn("from factory")
        });

        let resp = mock.create_message(empty_request()).await.unwrap();
        let text = match &resp.content[0] {
            ContentBlock::Text { text, .. } => text.clone(),
            _ => panic!("expected text"),
        };

View on GitHub (pinned to 433685b202)