Skip to content

Commit 2b818e0

Browse files
grdsdevclaude
andauthored
fix(storage): Resolve MultipartRequest finalization error in retry mechanism (#1208)
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]>
1 parent e8d40d6 commit 2b818e0

File tree

1 file changed

+19
-10
lines changed

1 file changed

+19
-10
lines changed

packages/storage_client/lib/src/fetch.dart

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,21 @@ class Fetch {
159159
StorageRetryController? retryController,
160160
) async {
161161
final headers = options?.headers ?? {};
162-
final request = http.MultipartRequest(method, Uri.parse(url))
163-
..headers.addAll(headers)
164-
..files.add(multipartFile)
165-
..fields['cacheControl'] = fileOptions.cacheControl
166-
..headers['x-upsert'] = fileOptions.upsert.toString();
167-
if (fileOptions.metadata != null) {
168-
request.fields['metadata'] = json.encode(fileOptions.metadata);
169-
}
170-
if (fileOptions.headers != null) {
171-
request.headers.addAll(fileOptions.headers!);
162+
163+
// Create a factory function that generates a fresh MultipartRequest for each attempt
164+
http.MultipartRequest createRequest() {
165+
final request = http.MultipartRequest(method, Uri.parse(url))
166+
..headers.addAll(headers)
167+
..files.add(multipartFile)
168+
..fields['cacheControl'] = fileOptions.cacheControl
169+
..headers['x-upsert'] = fileOptions.upsert.toString();
170+
if (fileOptions.metadata != null) {
171+
request.fields['metadata'] = json.encode(fileOptions.metadata);
172+
}
173+
if (fileOptions.headers != null) {
174+
request.headers.addAll(fileOptions.headers!);
175+
}
176+
return request;
172177
}
173178

174179
final http.StreamedResponse streamedResponse;
@@ -178,6 +183,10 @@ class Fetch {
178183
() async {
179184
attempts++;
180185
_log.finest('Request: attempt: $attempts $method $url $headers');
186+
187+
// Create a fresh request for each retry attempt
188+
final request = createRequest();
189+
181190
if (httpClient != null) {
182191
return httpClient!.send(request);
183192
} else {

0 commit comments

Comments
 (0)