Skip to content

Multipart uploads buffer the full request body in memory #18

@fallintoplace

Description

@fallintoplace

Summary

Multipart uploads currently build the entire request body in memory before sending it. That means a large file upload can turn into a large memory spike, even though the file-handling path uses reader-backed values that look like they should stream.

I checked this on main at 9eb2084.

What I found

Why this matters

For endpoints that accept large files, the CLI can end up holding the full encoded multipart request in memory. That can make uploads slower than necessary, increase RSS significantly, or fail in constrained environments. There is also a small file descriptor leak risk because the upload file is opened for encoding but not closed by the normal request path.

Possible fix

A good direction would be to stream multipart encoding with io.Pipe, so file contents are copied into the HTTP request as the client reads the body. The writer side should close owned upload files after each file reader is copied, while preserving the existing stdin behavior for @- / - inputs.

One wrinkle: the current bytes.Buffer body is replayable by the Go SDK for retries. A plain streaming pipe body would not be replayable, so the fix should make that behavior explicit. A few options:

  1. Disable automatic retries for streamed multipart bodies.
  2. Add a replayable multipart body that can reopen owned files for each retry.
  3. Spool the encoded multipart body to a temporary file when replayability is required.

The second option is probably the most complete long-term fix. The first option may be enough for a smaller CLI-side change if the retry tradeoff is acceptable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions