sigoden/aichat · error · anyhow::Error

Failed to read json stream

Error message

Failed to read json stream, {err}

What it means

In src/client/stream.rs `json_stream` iterates an async byte stream and wraps any per-chunk transport failure with `Failed to read json stream, {err}`. It indicates the HTTP/byte stream carrying the JSON (e.g. a Gemini streaming completion) broke mid-read, before the JSON could be parsed.

Solutions

  1. Retry the request; streaming drops are often transient.
  2. Check network/proxy stability (timeouts on corporate proxies commonly kill SSE streams).
  3. Reduce response size or use non-streaming mode if the network drops long streams.
  4. Inspect the inner error `{err}` for the root transport cause (e.g. hyper `IncompleteMessage`).
Defensive patterns

Strategy: retry

Try / catch

// Rust
match json_stream(...).await {
    Err(e) if e.to_string().contains("Failed to read json stream") => {
        // log inner cause, backoff, and retry the request
        retry_with_backoff(|| gemini_chat_completions_streaming(...)).await?;
    }
    other => other?,
}

Prevention

When it happens

Trigger: `json_stream` receives `Err(e)` from `stream.next().await` while consuming a streaming response (e.g. `gemini_chat_completions_streaming`): connection reset, timeout, proxy drop, TLS termination mid-body.

Common situations: Long-running LLM streaming responses dropped by flaky networks or proxies; server-side aborts; VPN/mobile connection changes mid-stream.

Related errors


AI-assisted analysis of sigoden/aichat@82976d349a (2026-09-09). Data as JSON: /api/errors/f56862efe35fda11. Report an issue: GitHub.

Appendix: source

Thrown at src/client/stream.rs:154

                }
                es.close();
            }
        }
    }
    Ok(())
}

pub async fn json_stream<S, F, E>(mut stream: S, mut handle: F) -> Result<()>
where
    S: Stream<Item = Result<bytes::Bytes, E>> + Unpin,
    F: FnMut(&str) -> Result<()>,
    E: std::error::Error,
{
    let mut parser = JsonStreamParser::default();
    let mut unparsed_bytes = vec![];
    while let Some(chunk_bytes) = stream.next().await {
        let chunk_bytes =
            chunk_bytes.map_err(|err| anyhow!("Failed to read json stream, {err}"))?;
        unparsed_bytes.extend(chunk_bytes);
        match std::str::from_utf8(&unparsed_bytes) {
            Ok(text) => {
                parser.process(text, &mut handle)?;
                unparsed_bytes.clear();
            }
            Err(_) => {
                continue;
            }
        }
    }
    if !unparsed_bytes.is_empty() {
        let text = std::str::from_utf8(&unparsed_bytes)?;
        parser.process(text, &mut handle)?;
    }

    Ok(())
}

View on GitHub (pinned to 82976d349a)