Skip to content

Conversation

grdsdev
Copy link
Contributor

@grdsdev grdsdev commented Aug 11, 2025

What kind of change does this PR introduce?

Bug fix

What is the current behavior?

When using StorageRetryController with file uploads, if the upload fails and triggers a retry, the SDK throws a Bad state: Can't finalize a finalized Request error. This occurs because the retry mechanism attempts to reuse an already-finalized MultipartRequest object.

The issue happens in the _handleMultipartRequest method in fetch.dart where:

  1. The first upload attempt creates and sends a MultipartRequest (which finalizes it)
  2. If it fails, the retry mechanism attempts to send the same request object again
  3. Since MultipartRequest objects cannot be finalized twice, this throws a StateError

This makes the retry functionality unusable for multipart uploads, particularly problematic for large file uploads on unstable connections.

What is the new behavior?

The retry logic now creates a fresh MultipartRequest for each retry attempt. This is accomplished by:

  • Introducing a createRequest() factory function that generates new MultipartRequest objects with all necessary configuration
  • Moving the request creation inside the retry closure so each attempt gets a brand new request
  • Preserving all existing functionality including headers, metadata, and file options

Now failed uploads can be successfully retried without encountering finalization errors, making StorageRetryController reliable for handling network failures during file uploads.

Additional context

  • All existing retry tests now pass (they were previously failing due to this bug)
  • The fix maintains backward compatibility and doesn't change any public APIs
  • This resolves issues with large file uploads on unstable network connections
  • The solution follows the same pattern used in other HTTP client retry implementations

Related to the retry functionality introduced in previous versions where this edge case wasn't properly handled.

…etry mechanism

When using StorageRetryController, failed uploads would trigger retries that attempted to reuse the same MultipartRequest object. Since MultipartRequest objects become finalized after the first send() call, subsequent retry attempts would throw "Can't finalize a finalized Request" StateError.

This fix creates a fresh MultipartRequest for each retry attempt by introducing a createRequest() factory function that generates new request objects with all the necessary headers, files, and fields configured correctly.

Fixes the retry functionality for file uploads with StorageRetryController, making it reliable for handling network failures during large file uploads.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@coveralls
Copy link

Pull Request Test Coverage Report for Build 16878888589

Details

  • 10 of 11 (90.91%) changed or added relevant lines in 1 file are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.01%) to 80.633%

Changes Missing Coverage Covered Lines Changed/Added Lines %
packages/storage_client/lib/src/fetch.dart 10 11 90.91%
Totals Coverage Status
Change from base Build 16305074338: 0.01%
Covered Lines: 3106
Relevant Lines: 3852

💛 - Coveralls

@grdsdev grdsdev requested review from Copilot, Vinzent03 and dshukertjr and removed request for Copilot and Vinzent03 August 11, 2025 12:17
Copy link

@Copilot 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 critical bug in the storage client's retry mechanism where MultipartRequest objects were being reused across retry attempts, causing "Can't finalize a finalized Request" errors. The solution creates a fresh MultipartRequest for each retry attempt by introducing a factory function that generates new request objects with identical configuration.

  • Introduces a createRequest() factory function to generate fresh MultipartRequest objects
  • Moves request creation inside the retry closure to ensure each attempt gets a new request
  • Maintains all existing functionality while making retry mechanism reliable for file uploads

@grdsdev grdsdev requested a review from Vinzent03 August 11, 2025 12:24
@grdsdev grdsdev merged commit 2b818e0 into main Aug 19, 2025
15 checks passed
@grdsdev grdsdev deleted the guilherme/clibs-287-supabase-flutter-storageretrycontroller-causes-cant-finalize branch August 19, 2025 12:14
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