Skip to content

fix: coerce nested BaseModel fields - #295

Merged
jbeckwith-oai merged 4 commits into
openai:mainfrom
bjedrocha:fix/base-model-nested-coercion
Aug 11, 2026
Merged

fix: coerce nested BaseModel fields#295
jbeckwith-oai merged 4 commits into
openai:mainfrom
bjedrocha:fix/base-model-nested-coercion

Conversation

@bjedrocha

@bjedrocha bjedrocha commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes nested BaseModel coercion so generated setters store successfully coerced model values instead of preserving raw hashes and arrays.

Root cause

The generated setter assigned the return value of Hash#store to error. Because Hash#store returns the value it stores, the successful branch that stored coerced was unreachable.

Composite converters also shared one mutable error slot. A later successful field or collection item could clear an earlier error, while a rejected union variant could overwrite the error state of the selected variant.

Changes

  • Store successfully coerced nested models and collections.
  • Preserve identity for values that already satisfy their target type.
  • Preserve raw input and conversion errors when any model field, array item, or map value fails coercion.
  • Isolate errors from rejected union variants and retain the selected variant's state.
  • Preserve existing model identity during direct BaseModel coercion.
  • Preserve union strictness for discriminator-resolved variants.

Before / after

require "openai"

class Item < OpenAI::BaseModel
  required :name, String
end

class Container < OpenAI::BaseModel
  required :item, Item
  required :items, OpenAI::ArrayOf[Item]
end

container = Container.new(
  item: {name: "single"},
  items: [{name: "array"}]
)

Before this fix, the generated setter returned raw hashes:

container.item.class
# => Hash

container.items.first.class
# => Hash

After this fix, successful coercion is stored:

container.item.class
# => Item

container.items.first.class
# => Item

Validation

  • ./scripts/test — 437 runs, 1,359 assertions, 0 failures
  • ./scripts/lint — RuboCop, Sorbet, and Steep all pass

Store coerced nested model values during BaseModel construction and assignment
instead of preserving raw hashes. Add coverage for nested model fields and arrays.
@bjedrocha
bjedrocha requested a review from a team as a code owner July 5, 2026 02:31
@jbeckwith-oai jbeckwith-oai added the generator Touches generated SDK files label Jul 16, 2026
@jbeckwith-oai jbeckwith-oai changed the title Fix BaseModel nested model coercion fix: coerce nested BaseModel fields Aug 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 110b3660c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread lib/openai/internal/type/base_model.rb

@HAYDEN-OAI HAYDEN-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 nested model coercion changes, including collection error aggregation, union isolation, identity preservation, and the follow-up nullable collection fix. No substantive issues found.

@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Aug 11, 2026
Merged via the queue into openai:main with commit e5152a9 Aug 11, 2026
12 checks passed
@openai-sdks openai-sdks Bot mentioned this pull request Aug 10, 2026
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.

3 participants