cloudflare/quiche · error
Expected stream_send on stream
Error message
Expected stream_send on stream {} to succeed, but got: {:?} What it means
h3i's execute_action validates each StreamSend action against the user-declared ExpectedStreamSendResult. When the expectation is Ok (or OkExact) but quiche's stream_send returns an error, the client panics with the stream id and the quiche::Error. It signals that the action script's expectation did not match actual connection state.
Solutions
- Check the reported quiche::Error: InvalidStreamState means the stream is closed/reset; FlowControl/StreamLimit means windows or limits are exhausted.
- Update ExpectedStreamSendResult in the action file to match reality (e.g. expect the specific error), or remove the action.
- Send less data per action or await capacity before stream_send if flow control is the cause.
- Verify the stream id exists and was opened successfully by a prior action.
Example fix
// before (action file)
StreamSend { stream_id: 0, data: ..., expected: Ok }
// after (stream may be reset by peer)
StreamSend { stream_id: 0, data: ..., expected: Err(Error::InvalidStreamState) } Defensive patterns
Strategy: validation
Validate before calling
// Before a send action, ensure the stream is open and window allows it: // in h3i action files, set expected to Err(..) for streams the peer may reset, // and avoid sending more than max_datagram/flow-control capacity.
Prevention
- Match ExpectedStreamSendResult to the actual stream lifecycle in your action file.
- Avoid large sends without regard to flow-control windows.
- Reference only stream ids created by earlier successful actions.
- Run action scripts against a local quiche-server to iterate quickly.
When it happens
Trigger: Executing an h3i action file whose stream_send action expects success while the stream is not writable: stream already closed/reset, flow-control window exhausted, invalid stream id, or send window is zero.
Common situations: Hand-written action scripts targeting streams that the peer has reset; sending more bytes than connection/stream flow control allows; referencing a stream created by an earlier failed action.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Expected stream_send on stream
- Expected stream_send on stream
- Expected stream_send on stream
- Expected stream_send on stream
- Error creating qlog file attempted path was
AI-assisted analysis of cloudflare/quiche@9f96daa2c2 (2026-09-08).
Data as JSON: /api/errors/08cc972864c5c441.
Report an issue: GitHub.
Appendix: source
Thrown at h3i/src/client/mod.rs:116
pub(crate) trait Client {
/// Gives mutable access to the stream parsers to update their state.
fn stream_parsers_mut(&mut self) -> &mut StreamParserMap;
/// Handles a response frame. This allows [`Client`]s to customize how they
/// construct a [`StreamMap`] from a list of frames.
fn handle_response_frame(&mut self, stream_id: u64, frame: H3iFrame);
}
pub(crate) type StreamParserMap = HashMap<u64, FrameParser>;
fn validate_stream_send_result(
result: quiche::Result<usize>, expected: &ExpectedStreamSendResult,
stream_id: u64,
) {
match expected {
ExpectedStreamSendResult::Ok => {
result.unwrap_or_else(|err| {
panic!(
"Expected stream_send on stream {} to succeed, but got: {:?}",
stream_id, err
)
});
},
ExpectedStreamSendResult::OkExact(expected_bytes) => {
match result {
Ok(actual_bytes) if actual_bytes == *expected_bytes => {},
Ok(actual_bytes) => panic!(
"Expected stream_send on stream {} to write {} bytes, got {}",
stream_id, expected_bytes, actual_bytes
),
Err(err) => panic!(
"Expected stream_send on stream {} to write {} bytes, got error: {:?}",
stream_id, expected_bytes, err
),
}
},View on GitHub (pinned to 9f96daa2c2)