Repository navigation
Registry downloads give up after 60 s even while the body is still arriving #872
Description
Activity
- added a commit that references this issue
on Oct 5, 2026 - addedbugSomething isn't workingSomething isn't workingarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)Filed by a scheduled architecture audit routine (see the architecture review discussion)
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Triaged as
priority:p1: the 60 s whole-request deadline inregistry_fetch::build_registry_clientis used by hosted upstream restore of npm tarballs (npm-family), plus Go zips, NuGet and vendored Maven, so the highest tier applies. Confirmed on main0d302dc:registry_fetch.rs:48andmaven_repo.rs:1405both set.timeout(Duration::from_secs(60))with no connect bound. Not a duplicate; no open PR touchesregistry_fetch. Standalone root cause (no cluster with other open issues; #676 explicitly excludesRegistryClient).
Generated by Claude Code
- added a commit that references this issue
on Oct 5, 2026 mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue for the architecture refactor routine (highest leverage: p1 bug fixed by moving the registry clients onto
ApiTimeoutsand deleting the last hand-rolledread_cappedcopy and Maven's per-fetch client). Branch: arch-refactor/872-registry-timeouts. Claim-ID: 2026-10-05T17:56:09Z-58ef60
Generated by Claude Code
mikolalysenko commented
on Oct 5, 2026 CollaboratorAuthorMore actions
[agent] Filed by the scheduled architecture audit routine (CLI and core). Register: register comment.
Kind: bug. Source: new finding, register row C49. It relates to C15: tracking issue #676 leaves
RegistryClientout of scope.Problem (main @
0d302dc)socket-patch has one stated HTTP transport policy,
api::retry::ApiTimeouts: a 10 s connect bound, plus 60 s of silence that resets on every chunk, with no total deadline. #581 chose this so that large bodies can stream for as long as they keep making progress.The registry clients don't use it. They set a whole-request deadline instead:
registry_fetch::build_registry_clientcalls.timeout(Duration::from_secs(60))and sets no connect bound. Hosted upstream restore (UpstreamClient::new,run by `rollback` and the `vendor` takeover via [`upstream/mod.rs#L574`](https://github.com/SocketDev/socket-patch/blob/0d302dcbe37729413f82c2fcd09cf1fe1a142c41/crates/socket-patch-core/src/patch/redirect/upstream/mod.rs#L574``)) uses that client to download npm tarballs (L287),Go module zips ([L410](https://github.com/SocketDev/socket-patch/blob/0d302dcbe37729413f82c2fcd09cf1fe1a142c41/crates/socket-patch-core/src/patch/redirect/upstream/client.rs#L409-L413))`` and NuGet registration documents. Each download is allowed up toMAX_DOWNLOAD_BYTES= 128 MiB, so the full cap fits in 60 s only at about 2.2 MB/s.fetch_registry_bytesbuilds a fresh client for every fetch, also with.timeout(60 s), and uses it to download the original jar (up to 128 MiB; L1164).``Next to this,
registry_fetch::downloadis the last hand-rolled copy ofutils::http::read_capped: the same declared-length check and streamed cap, with different messages. Maven, self-update, the vendor service andvlt_preflightalready use the shared reader.Proof by execution. This was a temporary core integration test, run twice on
0d302dcand not committed. A local server answers 200 withContent-Lengthand then sends a 64 KiB chunk every second for 70 s, which is a slow but steady download. Both clients read the same URL at the same time:The second run gave identical results (60.0015 s and 69.099 s). The registry client aborted a transfer that was still progressing; the
ApiTimeoutsclient finished it.Symptoms
None filed. Impact:
rollback(or a takeover) of a hosted pin whose original artifact takes more than 60 s to download fails with a transport error.Proposed change
build_registry_clientbuilds throughApiTimeouts::default().apply(...)(connect + idle read) instead of.timeout(60 s).maven_repo::fetch_registry_bytesreuses that client, built once per process, instead of building one per fetch.registry_fetch::downloadkeeps its http(s) scheme check and then callsutils::http::read_capped(resp, MAX_DOWNLOAD_BYTES, "registry artifact").registry_fetch::download, and the secondClient::builder()inmaven_repo.rs.Size and scope
About −35/+10 production lines in
vendor/registry_fetch.rsandvendor/maven_repo.rs, plus tests.Out of scope:
Acceptance criteria
grep -n "from_secs(60)" crates/socket-patch-core/src/vendor/registry_fetch.rs crates/socket-patch-core/src/vendor/maven_repo.rsfinds no client timeout.grep -c "Client::builder" crates/socket-patch-core/src/vendor/maven_repo.rsprints 0 outside tests.registry_fetch::download. Shorten the bounds with a test-only override rather than waiting 60 s.download_refuses_lying_content_lengthanddownload_caps_streamed_bytes_without_content_lengthtests stay green. Message assertions may change to theread_cappedwording.Dependencies
None. It doesn't conflict with #676/#677, which touch only
api/client.rs. E29 (movingregistry_fetch.rsout ofvendor/) would carry this along.