cloudflare/quiche · error

Expected stream_send on stream

Error message

Expected stream_send on stream {} to fail with {:?}, but wrote {} bytes

What it means

h3i panics when a script expected stream_send to fail with a specific error, but the write unexpectedly succeeded and produced bytes. The stream was actually writable, so the preconditions the script assumed (closed stream, exhausted flow control) did not hold. This is a negative-test assertion failure in the h3i harness.

Solutions

  1. Verify the stream's actual state (is it closed/reset/over flow-control limit?) and correct the stream_id in the script.
  2. If the send should legitimately succeed, change the expectation to an OkExact/OkAny variant.
  3. Check peer settings (MAX_STREAM_DATA, initial limits) that may allow the write; tighten the scenario setup to actually block the stream.

Example fix

// before
ExpectedStreamSendResult::Error(quiche::h3::Error::StreamStopped),
// after
ExpectedStreamSendResult::OkAny,
Defensive patterns

Strategy: validation

Validate before calling

// confirm the failure precondition actually holds
debug_assert!(!conn.stream_writable(stream_id, needed).unwrap_or(true));

Prevention

When it happens

Trigger: ExecuteAction with ExpectedStreamSendResult::Error(e) where quiche stream_send returns Ok(written) on the given stream_id.

Common situations: Assuming a stream was reset or flow-control-blocked when the peer had already granted capacity; quiche version changes altering error behavior; wrong stream_id targeted so the failing stream was never touched.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of cloudflare/quiche@9f96daa2c2 (2026-09-08). Data as JSON: /api/errors/d719eb53dac45dd7. Report an issue: GitHub.

Appendix: source

Thrown at h3i/src/client/mod.rs:137

                )
            });
        },
        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
                ),
            }
        },
        ExpectedStreamSendResult::Error(expected_err) => {
            match result {
                Ok(written) => panic!(
                    "Expected stream_send on stream {} to fail with {:?}, but wrote {} bytes",
                    stream_id, expected_err, written
                ),
                Err(actual_err) if &actual_err == expected_err => {},
                Err(actual_err) => panic!(
                    "Expected stream_send on stream {} to fail with {:?}, got {:?}",
                    stream_id, expected_err, actual_err
                ),
            }
        },
    }
}

pub(crate) fn execute_action<F: quiche::BufFactory>(
    action: &Action, conn: &mut quiche::Connection<F>,
    stream_parsers: &mut StreamParserMap,
) {
    match action {

View on GitHub (pinned to 9f96daa2c2)