hyperium / hyperium/h2

`h2::Error` hides IO error

Open
#862 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
1.6k
Forks
382
Avg merge
20h 23m
Merged PRs (30d)
9

Description

In uv, we want to retry streaming downloads on connection reset errors. These errors are common e.g. in GitHub Actions when downloading e.g. a 20MB file.

Our goal is to have a streaming download-and-unpack. We have a loop in which we try the streaming download-and-unpack, and if it fails, inspect the error chain on whether it looks like a retryable network error (https://github.com/astral-sh/uv/blob/22f80ca00d3f5af7d087154e998c886bbea8cee1/crates/uv-python/src/downloads.rs#L945-L993). This is easy for status code errors, where we get a reqwest::Error at the top of the error chain, but during the stream, the error may be nested in several layer of other crates involved in the unpacking, see the example error below.

We want to specifically retry io::ErrorKind::ConnectionReset. But when trying err.downcast_ref::<io::Error>() we don't get anything, as the h2 error wraps the IO error, which is not apparent from the debug output.

Tar(
    TarError {
        desc: "failed to unpack `/home/konsti/.local/share/uv/python/.temp/.tmpBHaUXj/python/bin/python3.12`",
        io: Custom {
            kind: Other,
            error: TarError {
                desc: "failed to unpack `python/bin/python3.12` into `/home/konsti/.local/share/uv/python/.temp/.tmpBHaUXj/python/bin/python3.12`",
                io: Custom {
                    kind: Other,
                    error: reqwest::Error {
                        kind: Decode,
                        source: reqwest::Error {
                            kind: Body,
                            source: Error {
                                inner: ErrorImpl {
                                    kind: Body,
                                    cause: Some(
                                        Error {
                                            kind: Io(
                                                Kind(
                                                    ConnectionReset,
                                                ),
                                            ),
                                        },
                                    ),
                                },
                            },
                        },
                    },
                },
            },
        },
    },
)

I'm also interested in ways to make our transient network error detection (https://github.com/astral-sh/uv/blob/f88aaa8740824b03be36c7ff106a139151452165/crates/uv-client/src/base_client.rs#L983-L1067) more reliable in general, without going through reqwest's error chain.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the error-chain handling described in crates/uv-python/src/downloads.rs lines 945-993 and crates/uv-client/src/base_client.rs lines 983-1067, then trace how the h2 error hides the nested IO error. Done means callers can reliably identify io::ErrorKind::ConnectionReset in streaming download failures without depending on reqwest-specific error inspection.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
networking
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
28/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.