Skip to content

fix: preserve binary multipart chunks - #324

Closed
Guflly wants to merge 1 commit into
openai:mainfrom
Guflly:fix/multipart-binary-chunks
Closed

fix: preserve binary multipart chunks#324
Guflly wants to merge 1 commit into
openai:mainfrom
Guflly:fix/multipart-binary-chunks

Conversation

@Guflly

@Guflly Guflly commented Aug 3, 2026

Copy link
Copy Markdown

Summary

  • normalize multipart enumerator chunks to binary before buffering
  • keep bounded and whole-stream reads in binary encoding
  • add regression tests for mixed UTF-8 and binary chunks

Fixes #317.

Validation

  • focused adapter tests pass
  • RuboCop passes
  • the full util test file has one existing Windows CGI filename failure, reproduced on current main

@Guflly
Guflly requested a review from a team as a code owner August 3, 2026 01:59
@jbeckwith-oai jbeckwith-oai added the generator Touches generated SDK files label Aug 3, 2026

@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.

Reviewed the adapter and all production call sites. Converting enumerated chunks to ASCII-8BIT before buffering preserves the exact bytes, eliminates UTF-8/BINARY compatibility failures, and leaves IO/StringIO behavior and transport framing unchanged. Bounded reads remain streaming with memory limited to the current source chunk/buffer; the unbounded-read path retains its existing whole-stream semantics. Regression coverage exercises both bounded and whole-stream mixed-encoding reads. Local validation: util suite 38/38 (160 assertions), focused mixed-encoding tests, an end-to-end multipart text+binary byte-integrity probe, RuboCop on both changed files, and git diff --check all pass.

Copy link
Copy Markdown
Contributor

Thank you very much for tracking this down and putting together the focused mixed-encoding fix, @Guflly. Normalizing every multipart Enumerator chunk to binary was the essential missing piece for #317, and your reproduction made the UTF-8-followed-by-binary failure concrete and straightforward to verify.

We carried that exact insight into #354 and combined it with the complete ReadIOAdapter contract repair: byte-limited reads, buffered and unbounded reads, EOF, negative lengths, output buffers, and native IO delegation. The canonical version is rebased onto current main in the SDK-owned adapter file and is now fully green across the Ruby matrix, lint, signatures, packaging, and CodeQL, with a real 1 MiB multipart upload verified byte-for-byte.

I’m closing this PR because #354 supersedes it. Your contribution was crucial to the final fix, and we genuinely appreciate the clear report, targeted implementation, and regression coverage. Thank you! 🙏

jbeckwith-oai added a commit to fallintoplace/openai-ruby that referenced this pull request Aug 10, 2026
## Summary

- preserve arbitrary binary bytes when multipart request bodies yield a
mix of UTF-8 and binary chunks
- honor `IO#read(max_len, out_string)` byte limits, buffering, EOF,
negative-length, and output-buffer semantics for Enumerator-backed
bodies
- retain native `IO` and `StringIO` delegation, including implicit
`to_int` length conversion
- update RBI/RBS contracts and add focused regression coverage

This fixes openai#317 and consolidates the complete behavior needed from openai#275,
openai#294, and openai#324 on the current SDK-owned `ReadIOAdapter` implementation.

## Ownership

This is handwritten SDK runtime behavior introduced as an SDK-owned
component in openai#345. It does not change OpenAPI inputs, Castiron facts,
renderer rules, templates, or generator configuration.

## Validation

- `mise exec ruby@4.0.6 -- ./scripts/test` — 531 runs, 1,736 assertions,
0 failures
- `mise exec ruby@4.0.6 -- bundle exec rake lint` — RuboCop, Sorbet, and
1,211 RBS files clean
- `mise exec ruby@4.0.6 -- bundle exec rake build:gem`
- installed-gem adapter probe
- Ruby 3.3.12 mixed-encoding compatibility probe
- 1,000 randomized read sequences compared against `StringIO`
- real local HTTP multipart upload with a 1 MiB binary file and UTF-8
prompt, verified byte-for-byte by SHA-256
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

generator Touches generated SDK files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Encoding::CompatibilityError during multipart file upload is swallowed and reported as a generic APIConnectionError ("Connection error.")

2 participants