🤖 Found by Claude ultrareview — automated high-effort code review. Please verify independently before acting.
Location: impit-python/src/response.rs:158 (PyResponseAsyncBytesIterator::__anext__)
A mid-stream body error is mapped to PyStopAsyncIteration:
Some(Err(e)) => {
if let Some(parent) = parent_response {
Python::attach(|py| {
if let Ok(mut parent_ref) = parent.try_borrow_mut(py) {
parent_ref.inner_state = InnerResponseState::StreamingClosed;
parent_ref.is_closed = true;
}
});
}
Err(pyo3::exceptions::PyStopAsyncIteration::new_err(format!(...)))
}
Impact: Raising StopAsyncIteration signals normal end-of-iteration to async for. So a connection reset or truncated chunked transfer mid-body silently ends the loop as if the stream completed, and the caller processes a partial body believing it is complete — a silent data-integrity bug. The error message is formatted into the exception but async for never surfaces it.
Additionally, unlike the clean-EOF branch, this path leaves is_stream_consumed = false, so a subsequent read()/content/text reports StreamClosed instead of the real failure.
Suggested direction: propagate stream errors as a real exception type (the classified ImpitError), not StopAsyncIteration, and set the consumed/closed flags consistently with the EOF branch.
Location:
impit-python/src/response.rs:158(PyResponseAsyncBytesIterator::__anext__)A mid-stream body error is mapped to
PyStopAsyncIteration:Impact: Raising
StopAsyncIterationsignals normal end-of-iteration toasync for. So a connection reset or truncated chunked transfer mid-body silently ends the loop as if the stream completed, and the caller processes a partial body believing it is complete — a silent data-integrity bug. The error message is formatted into the exception butasync fornever surfaces it.Additionally, unlike the clean-EOF branch, this path leaves
is_stream_consumed = false, so a subsequentread()/content/textreportsStreamClosedinstead of the real failure.Suggested direction: propagate stream errors as a real exception type (the classified
ImpitError), notStopAsyncIteration, and set the consumed/closed flags consistently with the EOF branch.