Skip to content

fal_client: sync MultipartUpload.save uploads empty bytes for every part after the first #1146

Description

@arthi-arumugam-git

The defect

projects/fal_client/src/fal_client/client.py, sync MultipartUpload.save: the per-part slice is assigned back onto data itself.

for part_number in range(1, parts + 1):
    start = (part_number - 1) * multipart.chunk_size
    data = data[start : start + multipart.chunk_size]
    futures.append(
        executor.submit(multipart.upload_part, part_number, data)
    )

Iteration 1 replaces the full buffer with its first chunk, so iteration 2 computes start = chunk_size and slices the now chunk-sized buffer, yielding b"". Every part from 2 to N is uploaded as zero bytes, while the part count and ETag bookkeeping stay well formed, so nothing raises and the stored object is silently truncated to the first chunk.

The async twin, AsyncMultipartUpload.save, does the same operation correctly with a separate variable: chunk = data[start : start + multipart.chunk_size]. Both save_file variants are also correct. Only the sync bytes path reuses the name data.

Repro

Upload a payload larger than MULTIPART_THRESHOLD (100MB) through fal_client.SyncClient.upload as bytes, download it back, compare hashes: the object is truncated to the first 10MB chunk. Present since the multipart feature landed (#413, Feb 2025). Existing unit tests mock MultipartUpload.save itself, so the loop has no coverage.

Fix, ready on a fork

Two-line fix mirroring the async implementation plus a regression test that captures (part_number, data) pairs across a 3-part payload. Against the current code the test fails with parts 2 and 3 empty; with the fix the full fal_client unit suite passes (99 passed).

Branch: https://github.com/arthi-arumugam-git/fal/tree/fix/sync-multipart-empty-chunks (commit f55e790, diff: main...arthi-arumugam-git:fal:fix/sync-multipart-empty-chunks)

Pull request creation on this repository is limited to collaborators, so the fix is linked here instead. Happy to open the PR if access is enabled, or maintainers are welcome to cherry-pick the commit.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions