Fix corrupted or incomplete files after interrupted download - #359
Merged
iLLiCiTiT merged 3 commits intoSep 14, 2026
Merged
Conversation
- Download continuation with 'Range' header did not check the response is partial content (206). A server ignoring 'Range' sends the whole file, which was appended to already downloaded content. - Downloaded size was never compared to 'Content-Length', so a download closed before all content was received was accepted as complete. It is now continued as another attempt, also on ChunkedEncodingError. - 'Content-Length' was stored as string and missing header raised KeyError. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
BigRoy
added this pull request to stack #362
September 12, 2026 22:18
BigRoy
removed this pull request from stack #362
September 14, 2026 14:41
BigRoy
marked this pull request as ready for review
September 14, 2026 14:43
There was a problem hiding this comment.
🟡 Changes recommended
Clear the stale Range header after resetting progress and add the requested chunked-error regression test.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Fixes resumable downloads by detecting incomplete responses, handling ignored ranges, and supporting missing Content-Length headers.
Changes:
- Resets partial output when resumed responses are not
206. - Validates transfer sizes and retries incomplete downloads.
- Adds regression tests for interrupted and range-ignored downloads.
File summaries
| File | Summary |
|---|---|
tests/test_download_resume.py |
Adds interrupted-download regression coverage. |
ayon_api/server_api.py |
Implements resume integrity checks and retry handling; a critical stale Range header issue remains, and ChunkedEncodingError coverage is missing. |
Review details
Suppressed comments (1)
ayon_api/server_api.py:1723
- The new
ChunkedEncodingErrorbranch is not exercised by these regression tests: allFakeResponseiterators complete normally, so a future removal or misordering of this exception handler could go unnoticed. Add a response/iterator that raisesChunkedEncodingErrorafter yielding a prefix and assert the retry uses theRangeoffset and produces the complete content.
requests.exceptions.ChunkedEncodingError,
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
iLLiCiTiT
reviewed
Sep 14, 2026
iLLiCiTiT
approved these changes
Sep 14, 2026
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.
Bug
When a download is interrupted and retried, the resulting file can be corrupted or incomplete without any error:
Range: bytes=<offset>-. If the server (or a proxy) ignoresRangeand answers200with the whole file, the whole file is appended after the already written part.ChunkedEncodingError, which wasn't caught), the download is reported as finished.Content-Lengthwas stored in progress as a string, and a response without it (chunked transfer) raisedKeyError.Cause
206 Partial Contentbefore appending.response.headers["Content-length"]was passed directly toset_content_size.Fix
offset > 0) and the response is not206, truncate the output stream and reset progress, then write the full content.ConnectionError, which is retried withRangelike other connection errors.ChunkedEncodingErroris retried as well.Content-Lengthis converted toint(for206the already downloaded offset is added) and a missing header is allowed.Reproduce
Hard to trigger on demand against a real server,
tests/test_download_resume.pysimulates:206,Range(develop result:b"01230123456789"),Content-Length(develop:KeyError).Testing notes
con.download_file(...)of a thumbnail/file gives identical bytes andprogress.content_sizeis now anint.limit_datatoxic), compare the checksum with the source file. Test once with a proxy that stripsRangeto cover the200case.🤖 Generated with Claude Code