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.
Version
h3 0.0.8,h3-webtransport 0.1.2Platform
Linux desktop 7.1.7 NixOS x86_64 GNU/Linux
Summary
AsyncWriteloses top-level typed stream-error classificationCode Sample
In contrast, polling the h3 trait directly returns the typed error:
Expected Behavior
The primary h3/WebTransport write path should preserve
StreamErrorIncomingdirectly, or the I/O adapter should document a stable recovery API and provide useful error-kind mapping where possible.Actual Behavior
BufRecvStreamimplements Tokio and futuresAsyncWriteby converting everyStreamErrorIncominginto:The source object is not irretrievably discarded: callers can recover it by downcasting
io::Error::get_ref(). However, the top-level type and meaningfulErrorKindclassification are lost. Generic code that handles onlyio::ErrorKindcannot distinguish a peer stream reset from whole-connection loss.Suggested upstream fix
Prefer typed h3 poll/future methods in public protocol APIs and make
AsyncWritean explicitly lossy compatibility adapter. If the adapter remains prominent, document source downcasting and map errors to meaningfulio::ErrorKindvalues where semantics are unambiguous.