Skip to content

fix(files): support filename for stream and byte-array multipart uploads - #740

Open
bsaptarshi wants to merge 2 commits into
openai:mainfrom
bsaptarshi:fix/issue-284-multipart-filename-stream-uploads
Open

fix(files): support filename for stream and byte-array multipart uploads#740
bsaptarshi wants to merge 2 commits into
openai:mainfrom
bsaptarshi:fix/issue-284-multipart-filename-stream-uploads

Conversation

@bsaptarshi

Copy link
Copy Markdown

Summary

Fixes multipart upload behavior for stream/byte file inputs by ensuring a filename is always present.

This addresses #284, where uploads using anonymous bytes/streams (for example, browser recordings) can fail because multipart filename is omitted.

Changes

1) Explicit filename overloads

Added filename-aware overloads in:

  • com.openai.models.files.FileCreateParams
  • com.openai.models.containers.files.FileCreateParams

New overloads:

  • file(InputStream file, String filename)
  • file(byte[] file, String filename)

2) Default filename fallback for anonymous uploads

Updated single-argument overloads to provide a safe default filename:

  • file(InputStream) now defaults to file.bin
  • file(byte[]) now defaults to file.bin

This keeps backward compatibility while improving behavior for anonymous stream/bytes sources.

3) Existing behavior retained

  • file(Path) behavior is unchanged and continues to use path.name as filename.
  • Multipart content type for binary file parts remains application/octet-stream.

4) Tests

Added/updated tests to verify:

  • default filename (file.bin) is applied for single-arg stream/bytes uploads
  • explicit filename is preserved when provided
  • multipart field content type remains application/octet-stream

Why

file(Path) already included multipart filename metadata, but file(InputStream) and file(byte[]) previously did not.
Some server-side file handling expects filename in multipart parts, causing failures for anonymous stream/bytes uploads.

Validation

Ran targeted tests for modified models:

./gradlew :openai-java-core:test \
  --tests com.openai.models.files.FileCreateParamsTest \
  --tests com.openai.models.containers.files.FileCreateParamsTest

@bsaptarshi
bsaptarshi requested a review from a team as a code owner May 8, 2026 10:48
@bsaptarshi

Copy link
Copy Markdown
Author

Hi @TomerAberbach,

Following up on Issue #284. I have added this PR to include default filename fallbacks (file.bin) for InputStream and byte[] overloads, plus new explicit filename overloads.

This should resolve the 400 errors for anonymous uploads while remaining backward compatible. Please help review the changes!

@bsaptarshi

bsaptarshi commented May 9, 2026

Copy link
Copy Markdown
Author

One more thing to add regarding the test failures. I confirmed they are unrelated to this PR and were already present on upstream/main.

I ran full tests on both:

  • upstream/main (without this change)
  • this branch (with this change)

The same baseline admin/org failures appear in both runs.
This PR only changes multipart filename handling for stream/byte uploads and related tests.

@bsaptarshi

Copy link
Copy Markdown
Author

Hi @TomerAberbach

Can you or someone take a look at this PR? If it's no.longer required feel free to update the issue and I'll retract this. Not sure what the plan is for this one.

@jbeckwith-oai jbeckwith-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two blockers:

  1. openai-java-core/src/main/kotlin/com/openai/models/files/FileCreateParams.kt:156file.bin is not a safe default for this endpoint. The model documentation immediately above says both Fine-tuning and Batch only accept .jsonl, and the README’s anonymous-stream example uses FilePurpose.FINE_TUNE. With this change, that example sends filename="file.bin", so the API still rejects the request. The new tests even pair FilePurpose.BATCH with file.bin, but only inspect the local MultipartField, masking that the resulting request is invalid. Different purposes require different extensions, so there is no universal fallback here. Please keep the explicit filename overloads, avoid presenting file.bin as a safe default for /files, and update the README/examples to use the new filename-aware overload (or otherwise make callers supply a purpose-appropriate filename).

  2. openai-java-core/src/test/kotlin/com/openai/models/files/FileCreateParamsTest.kt:107 — the branch fails the repository formatter. ./gradlew :openai-java-core:lintKotlin --no-daemon --no-parallel reports this file; the chained builder call needs ktfmt formatting.

Validation: the two targeted FileCreateParamsTest suites pass, and git diff --check passes, but :openai-java-core:lintKotlin fails as described.

@bsaptarshi

Copy link
Copy Markdown
Author

Thanks for reviewing @jbeckwith-oai

I ack and agree on the concern about file.bin being an unsafe default. But instead of the proposed alternative, I was thinking, could we do a purpose-aware default strategy? Something like

  • Provide appropriate defaults based on the purpose (e.g. *.jsonl for fine-tuning/batch, file.bin as fallback)
  • Add validation during build() to catch mismatches early
  • Maintain backward compatibility

This would keep the explicit overloads for users who need specific filenames. It also safeguards against future errors by validating the filename-purpose relationship at construction time.

Of course, the downside will be the maintenance overhead, and keeping mappings updated as these grow. But with changes to a single mapping class, we can avoid making several update across the repo. Additionally, the maintenance overhead sits with SDK owners, with infrequent updates to FileNameMapper, and not clients.

If we deprecate single-arg method, every client must update their code. But if we maintain the mapping, only SDK maintainers update FileNameMapper when purposes change.

It also becomes the single source of truth, with isolated tests, and should be easy to extend. Open to alternatives and suggestions if you disagree.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants