Skip to content

Rewind file streams before rate-limit retries - #2179

Open
CR29-22-2805 wants to merge 1 commit into
praw-dev:mainfrom
CR29-22-2805:fix-2178-rewind-file-streams
Open

Rewind file streams before rate-limit retries#2179
CR29-22-2805 wants to merge 1 commit into
praw-dev:mainfrom
CR29-22-2805:fix-2178-rewind-file-streams

Conversation

@CR29-22-2805

Copy link
Copy Markdown

Summary

Rewind seekable multipart file streams before retrying a POST request after a retryable RATELIMIT response.

Without rewinding, the first request consumes the stream and a retry may upload an empty or truncated file.

Changes

  • Record the initial position of seekable file streams passed to Reddit.post()
  • Restore those positions before each retry
  • Leave non-seekable streams unchanged
  • Add a regression test covering a rate-limit retry with a partially advanced BytesIO stream

Fixes #2178

Tests

  • python -m pytest tests/unit/test_reddit.py -k post_ratelimit
  • python -m pytest tests/unit/test_reddit.py

@CR29-22-2805
CR29-22-2805 force-pushed the fix-2178-rewind-file-streams branch 3 times, most recently from 9a8cc7e to e9b0358 Compare July 20, 2026 04:10

@bboe bboe left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is a well-scoped fix and the regression test starting the stream at a non-zero offset is a nice touch. Two things:

  1. Please add a CHANGES.rst entry under Unreleased — this is a user-visible bug fix.
  2. Silently skipping non-seekable streams leaves the original bug in the case that's hardest to diagnose. I'd note in the post() docstring that automatic retries only preserve seekable file objects.

Comment thread praw/reddit.py
Comment on lines +824 to +832
max_attempts = 3
attempts = max_attempts
last_exception: RedditAPIException | None = None
while attempts > 0:
attempts -= 1
if attempts < max_attempts - 1 and file_positions:
assert files is not None
for name, position in file_positions.items():
files[name].seek(position)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Equivalent behavior, but the loop counter reads more directly than the attempts < max_attempts - 1 arithmetic.

Suggested change
max_attempts = 3
attempts = max_attempts
last_exception: RedditAPIException | None = None
while attempts > 0:
attempts -= 1
if attempts < max_attempts - 1 and file_positions:
assert files is not None
for name, position in file_positions.items():
files[name].seek(position)
last_exception: RedditAPIException | None = None
for attempt in range(3):
if attempt and file_positions:
assert files is not None
for name, position in file_positions.items():
files[name].seek(position)

@bboe

bboe commented Jul 26, 2026

Copy link
Copy Markdown
Member

One more thing: if you'd like, please add yourself to AUTHORS.rst — it's listed as a step in contributing and you're not in there yet. New entries go just above the Add "Name <email (optional)> and github profile link" above this line. marker at the bottom, following the existing format:

- Your Name `@CR29-22-2805 <https://github.com/CR29-22-2805>`_

Entirely optional, but the contribution is worth the credit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

File uploads may be empty or truncated after a rate-limit retry

2 participants