Skip to content

Conversation

@rafaeljusto
Copy link
Contributor

Previously, DoExponentialBackoff relied on Seek to reset request bodies between retries. This approach failed when bodies didn't implement Seek or when req.GetBody wasn't set (e.g., manually wrapped io.NopCloser), causing "ContentLength=N with Body length 0" errors on retry attempts.

The issue occurred because req.Clone() reuses the exhausted body reader without resetting it, leading to empty bodies on subsequent attempts while ContentLength remained set from the original request.

Now read the entire request body upfront and create fresh io.Readers for each retry attempt. This ensures:

  • Body is always available for all retry attempts
  • ContentLength is correctly set to match the actual body
  • Works reliably with all io.Reader types, not just seekable ones

Added test case with io.NopCloser-wrapped bytes.Buffer that validates both body content and ContentLength matching across retry attempts.

Previously, DoExponentialBackoff relied on Seek to reset request bodies
between retries. This approach failed when bodies didn't implement Seek
or when req.GetBody wasn't set (e.g., manually wrapped io.NopCloser),
causing "ContentLength=N with Body length 0" errors on retry attempts.

The issue occurred because req.Clone() reuses the exhausted body reader
without resetting it, leading to empty bodies on subsequent attempts
while ContentLength remained set from the original request.

Now read the entire request body upfront and create fresh io.Readers
for each retry attempt. This ensures:
- Body is always available for all retry attempts
- ContentLength is correctly set to match the actual body
- Works reliably with all io.Reader types, not just seekable ones

Added test case with io.NopCloser-wrapped bytes.Buffer that validates
both body content and ContentLength matching across retry attempts.
@coveralls
Copy link

coveralls commented Jan 6, 2026

Pull Request Test Coverage Report for Build 20778351413

Details

  • 29 of 46 (63.04%) changed or added relevant lines in 1 file are covered.
  • 1 unchanged line in 1 file lost coverage.
  • Overall coverage decreased (-0.2%) to 76.703%

Changes Missing Coverage Covered Lines Changed/Added Lines %
httputilx/httputilx.go 29 46 63.04%
Files with Coverage Reduction New Missed Lines %
httputilx/httputilx.go 1 61.42%
Totals Coverage Status
Change from base Build 20759133771: -0.2%
Covered Lines: 1284
Relevant Lines: 1674

💛 - Coveralls

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes a bug in DoExponentialBackoff where request bodies would fail to be sent correctly on retry attempts. The previous implementation relied on Seek() to reset bodies between retries, which failed for non-seekable readers or when req.GetBody wasn't set, causing "ContentLength=N with Body length 0" errors.

Key changes:

  • Modified body handling to read the entire request body upfront and create fresh readers for each retry
  • Updated ContentLength to match the actual body size on each retry attempt
  • Added comprehensive test case validating body content and ContentLength across retries with io.NopCloser-wrapped bodies

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
httputilx/httputilx.go Replaced Seek-based body reset with upfront body reading and fresh reader creation for each retry
httputilx/httputilx_test.go Added test case to verify request bodies are correctly preserved across retry attempts

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rafaeljusto rafaeljusto marked this pull request as draft January 7, 2026 00:07
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@rafaeljusto rafaeljusto marked this pull request as ready for review January 7, 2026 10:35
@rafaeljusto rafaeljusto merged commit cbc65f0 into master Jan 7, 2026
10 checks passed
@rafaeljusto rafaeljusto deleted the httpx-exp-backoff branch January 7, 2026 10:35
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.

3 participants