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

  1. Check the reported quiche::Error: InvalidStreamState means the stream is closed/reset; FlowControl/StreamLimit means windows or limits are exhausted.
  2. Update ExpectedStreamSendResult in the action file to match reality (e.g. expect the specific error), or remove the action.
  3. Send less data per action or await capacity before stream_send if flow control is the cause.
  4. 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

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


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)