Skip to content

AsyncWrite reduces typed stream failures to io::ErrorKind::Other #353

Description

@spotdemo4

Version

h3 0.0.8, h3-webtransport 0.1.2

Platform

Linux desktop 7.1.7 NixOS x86_64 GNU/Linux

Summary

AsyncWrite loses top-level typed stream-error classification

Code Sample

use tokio::io::AsyncWriteExt;

// Arrange for the peer to reset/stop this stream, then write through the
// AsyncWrite adapter.
let err: std::io::Error = send.write_all(b"response").await.unwrap_err();
assert_eq!(err.kind(), std::io::ErrorKind::Other);

let typed = err
    .get_ref()
    .and_then(|source| source.downcast_ref::<h3::quic::StreamErrorIncoming>());
assert!(typed.is_some());

In contrast, polling the h3 trait directly returns the typed error:

let err = poll_fn(|cx| {
    h3::quic::SendStreamUnframed::poll_send(&mut send, cx, &mut bytes)
})
.await
.unwrap_err();

assert!(matches!(
    err,
    h3::quic::StreamErrorIncoming::StreamTerminated { .. }
));

Expected Behavior

The primary h3/WebTransport write path should preserve StreamErrorIncoming directly, or the I/O adapter should document a stable recovery API and provide useful error-kind mapping where possible.

Actual Behavior

BufRecvStream implements Tokio and futures AsyncWrite by converting every StreamErrorIncoming into:

std::io::Error::new(std::io::ErrorKind::Other, error)

The source object is not irretrievably discarded: callers can recover it by downcasting io::Error::get_ref(). However, the top-level type and meaningful ErrorKind classification are lost. Generic code that handles only io::ErrorKind cannot distinguish a peer stream reset from whole-connection loss.

Suggested upstream fix

Prefer typed h3 poll/future methods in public protocol APIs and make AsyncWrite an explicitly lossy compatibility adapter. If the adapter remains prominent, document source downcasting and map errors to meaningful io::ErrorKind values where semantics are unambiguous.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions