S3 UploadPartCopy failures leak reserved upload size

Open
#1,645 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

@hsusul is already working on this.

Since Nov 2, 2026.

  • #1646 by @hsusul — open

Assessment

Difficulty
3/5
Estimated time
Half a day
Newbie friendliness
42/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
postgresql, typescript
Domain
backend

Research direction

Start with the UploadPartCopy handler and shouldAllowPartUpload(), where the copy size is reserved in storage.s3_multipart_uploads.in_progress_size before the backend call and part-row insert. Compare against the existing UploadPart error path that already releases its reservation, and add the same release for backend and insert failures. Done when a retry of a failed copy under the 9-byte limit succeeds, and the reproduction steps in the issue pass.

Written by the indexing model from the issue text.

Description

Bug report

A failed UploadPartCopy leaves its bytes in storage.s3_multipart_uploads.in_progress_size. A valid retry can then fail with 413 EntityTooLarge before reaching the recovered backend.

The handler reserves the copy size through shouldAllowPartUpload(), then calls the backend and inserts the part row without an error cleanup path. Ordinary UploadPart failures already release their reservation.

To reproduce

  1. Create a bucket with a 9-byte file size limit and upload a 9-byte source object.
  2. Start a multipart upload for a different object.
  3. Make the backend fail one UploadPartCopy request, for example with a one-shot injected backend error.
  4. Retry the same copy after the backend recovers.

A local AWS SDK run against PostgreSQL 15 and RustFS, at upstream b74897cf, produced:

{"step":"after-failed-copy","progress":9}
EntityTooLarge: The object exceeded the maximum allowed size

The first request stored no part. Its retry still fails because the handler counts the failed copy's 9-byte reservation.

Expected behavior

Release the failed request's reservation while preserving bytes from other successful or active parts. The retry should fit the original limit and complete normally. A failed part-row insert after the backend copy needs the same cleanup.

Scope

This concerns failures after a copy reservation. It is separate from #1493/#1494, which checks source preconditions before reservation, and #1436/#1437, which covers duplicate part listings. Successful part replacement accounting and HTTP disconnect cleanup are outside this report.

Dominant language
TypeScript
Stars
1.3k
Forks
318
Avg merge
1d 15h
Merged PRs (30d)
104

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from supabase/storage

All issues in supabase/storage

Similar issues

More TypeScript issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.