SIGN IN SIGN UP

fix(uploads): detect multipart bodies from own properties only (#2492)

- [x] I understand that this repository is auto-generated and my pull
request may not be merged

## Changes being requested

`hasUploadableValue` and `hasStreamingUploadableValue` walk candidate
request bodies with `for...in`, which includes inherited enumerable
properties and triggers their getters. Every serializer is
own-property-only: `createForm` and the streaming encoder iterate
`Object.entries`, the generated multipart encoding checks
`hasOwnProperty`, and the JSON path is `JSON.stringify`. So detection
and serialization can disagree about what a body contains. A body whose
only `File` sits on its prototype chain flips the request to
`multipart/form-data` while the form omits the value that caused the
flip (reproduced with `containers.files.create`: an own `file_id` plus a
prototype `file` getter sent multipart containing only `file_id`, with
the foreign getter fired twice), and an inherited async iterable can
flip buffered encoding to the lazy streaming path. Under the old walk,
an inherited uploadable could never reach the wire under any encoding;
it could only corrupt the content-type choice and fire getters the
caller never exposed as own data.

This change makes both walkers iterate `Object.keys`, so detection
matches what every encoder actually serializes. Two regressions land
beside the existing "leaves requests without uploadable values
unchanged" test: an inherited `File` no longer flips the request (and
its getter is never read), and an own `File` plus an inherited streaming
value selects buffered `FormData` encoding with the inherited value
absent from the form.

The two remaining `for...in` walks in `src/` are intentionally
untouched: `isEmptyObj` in `internal/utils/values.ts` is correct as
written because inherited enumerable properties genuinely make an object
non-empty (its vendored twin documents exactly that intent), and the
vendored `zod-to-json-schema` utility is excluded from repository
policy.

Verified locally (Node 24.18.0): both regressions fail on `main` and
pass with this change; the uploads suite passes 61/61; lint, build, and
the full test suite pass (158 files).

## Additional context & links

Found while auditing the multipart detection path; the fix aligns
detection with the ownership contract every serializer in the module
already follows.
M
Morgan Carr committed
559ffc8079d0ae716bbf7915305e7db6ecc016a1
Parent: b5a13a7
Committed by GitHub <noreply@github.com> on 8/27/2026, 3:52:48 AM