Skip to content

Fix file transfers ignoring connection 'max_retries' - #358

Merged
iLLiCiTiT merged 7 commits into
developfrom
bugfix/transfer-max-retries
Sep 14, 2026
Merged

iLLiCiTiT merged 7 commits into
developfrom
bugfix/transfer-max-retries

Conversation

@BigRoy

@BigRoy BigRoy commented Sep 12, 2026

Copy link
Copy Markdown
Member

Bug

File uploads and downloads ignore the connection's max_retries and can end up making zero attempts:

  • con.set_max_retries(1) (or ServerAPI(..., max_retries=1)) has no effect on transfers; they always use the env variable / class default (3).
  • With AYON_SERVER_RETRIES=0:
    • uploads crash: AttributeError: 'NoneType' object has no attribute 'raise_for_status'
    • downloads silently do nothing — no request, no error, empty/missing file.

Cause

_upload_file and _download_file_to_stream used self.get_default_max_retries() instead of self.max_retries, and looped for attempt in range(retries) without ensuring at least one attempt. REST requests (_do_rest_request) already clamp to at least 1.

Fix

Use max(self.max_retries, 1) in both transfer functions.

Reproduce

AYON_SERVER_RETRIES=0 python -c "
import ayon_api
con = ayon_api.get_server_api_connection()
print(con.create_thumbnail('<project>', '/path/to/image.png'))
"
# develop: AttributeError: 'NoneType' object has no attribute 'raise_for_status'
# this PR: <thumbnail id>

Download with zero retries:

import io, ayon_api
con = ayon_api.get_server_api_connection()  # with AYON_SERVER_RETRIES=0
stream = io.BytesIO()
con.download_file_to_stream(f"api/projects/<project>/thumbnails/<thumbnail id>", stream)
print(len(stream.getvalue()))  # develop: 0

Testing notes

  • tests/test_transfer_max_retries.py: zero retries still uploads/downloads; max_retries=1 makes exactly one upload attempt.

Stacked PRs touching the same download/upload loop build on top of this branch.

🤖 Generated with Claude Code

BigRoy and others added 2 commits September 13, 2026 00:05
Uploads and downloads used 'get_default_max_retries()' (env variable or
class default) instead of the connection's 'max_retries', and did not
ensure at least one attempt. With 'AYON_SERVER_RETRIES=0' an upload
crashed with AttributeError on 'None' response and a download silently
did not download anything.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
- 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
BigRoy requested review from iLLiCiTiT and a lite review from Copilot and removed request for Copilot September 14, 2026 14:40
@BigRoy BigRoy self-assigned this Sep 14, 2026
@BigRoy BigRoy added the type: bug Something isn't working label Sep 14, 2026
@BigRoy
BigRoy marked this pull request as ready for review September 14, 2026 14:40
@BigRoy
BigRoy removed this pull request from stack #362 September 14, 2026 14:41
@iLLiCiTiT
iLLiCiTiT merged commit ecaafeb into develop Sep 14, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

type: bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants