fix: wire upload timeout_secs to HTTP read_timeout (fixes 499 on 50GB+ uploads)#53
Merged
Merged
Conversation
… on large uploads) The HTTP read_timeout in ImmichClient was hardcoded to 120s and never read the configured UploadConfig.timeout_secs. On a slow backend (Orange Pi / Rockchip SBC), Immich can spend several minutes checksumming a 50GB file after the last upload byte is sent; no response bytes arrive during that window, so the 120s inactivity timeout fires and the client aborts with HTTP 499 (client closed request). Fix: - Add timeout_secs: u64 param to with_bandwidth_limit; use it as .read_timeout(Duration::from_secs(timeout_secs)) instead of 120. - ImmichClient::new defaults to 3600s (same as the new config default). - src/main.rs: passes config.upload.timeout_secs to with_bandwidth_limit. - src/app.rs: apply_new_config now calls with_bandwidth_limit (was ::new) so bandwidth limit AND timeout both track the live config on server change. - src/config.rs: UploadConfig::default().timeout_secs 300 -> 3600 (1 hour); doc comment updated to describe inactivity-only semantics and why 1 hour is appropriate for 50GB+ uploads to slow servers. No overall .timeout() added -- a 50GB upload at 10MB/s legitimately streams for ~83 minutes; an overall timeout would kill healthy transfers. Only the inactivity (read) timeout is configurable. Users can raise timeout_secs in settings if their server is slower still. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Gumbees
added a commit
that referenced
this pull request
May 26, 2026
#53 (wire upload timeout_secs through to read_timeout, fixes 499s on large uploads) landed on development without a version bump — and 0.2.2 was already released at the prior tag. Bump to 0.2.3 so the dev->release push tags a fresh v0.2.3 and ships the fixed binary. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause
ImmichClient::with_bandwidth_limithardcoded.read_timeout(Duration::from_secs(120))and never read the configuredUploadConfig.timeout_secs. Theread_timeoutis an inactivity timeout -- it fires when no response bytes arrive for the configured duration. On a slow backend (Orange Pi / Rockchip SBC), Immich can spend several minutes checksumming a 50 GB file after receiving the last upload byte; no response bytes flow during that window. After 120 seconds of silence, reqwest fires the timeout and drops the connection -- the server sees a premature client close and returns HTTP 499. Thetimeout_secsconfig knob (intended to control this) was dead-wired: set in config, never passed to the client.Fix
src/api/mod.rs: addedtimeout_secs: u64param towith_bandwidth_limit;.read_timeoutnow uses it instead of the hardcoded 120s.ImmichClient::new(connection-test path used by settings/first-run UI) defaults to 3600s. Updated the comment block to explain that this is an inactivity-only timeout, deliberately NOT an overall timeout (a healthy 50 GB transfer at 10 MB/s takes ~83 min; an overall timeout would kill it).src/main.rs: passesconfig.upload.timeout_secstowith_bandwidth_limitat app startup.src/app.rs:apply_new_configswitched fromImmichClient::newtowith_bandwidth_limit, so both bandwidth limit and inactivity timeout track the live config when server settings change.src/config.rs:UploadConfig::default().timeout_secsraised from 300 to 3600 (1 hour); doc comment updated to describe inactivity-only semantics and the slow-backend use case.No overall
.timeout()was added -- the existing design deliberately omits it and that is preserved.Users can raise
timeout_secsin settings if their server needs more than an hour to process a single file.Born-green gate
All four CI gates pass locally.