Skip to content

keep aliases and inf/nan when ToJsonOptions is set - #2039

Merged
tconley1428 merged 1 commit into
temporalio:mainfrom
avanish-garg:fix/pydantic-tojsonoptions-wire-format
Oct 29, 2026
Merged

tconley1428 merged 1 commit into
temporalio:mainfrom
avanish-garg:fix/pydantic-tojsonoptions-wire-format

Conversation

@avanish-garg

Copy link
Copy Markdown
Contributor

What was changed

PydanticJSONPlainPayloadConverter now builds its serializer with config={"ser_json_inf_nan": "constants"} and passes by_alias=True to SchemaSerializer.to_json, so the to_json_options path produces the same bytes as the no-options path (pydantic_core.to_json). ToJsonOptions keeps its only effect, exclude_unset. Adds a changelog/fixed fragment.

Why?

Since pydantic 2.11, SchemaSerializer.to_json defaults to by_alias=False and writes inf/nan as null, unlike pydantic_core.to_json. With ToJsonOptions set, aliased fields were therefore encoded under their field name, so a receiver that accepts only the alias silently used the field default, and top-level/list/dict inf/nan became null.

Pydantic-core versions that do not know ser_json_inf_nan ignore the key, so no version guard is needed (checked on pydantic 2.0.3: default and options paths still match). Inf/nan inside model fields stay governed by the model config on both paths, as before.

Checklist

  1. Closes [Bug] Pydantic converter with ToJsonOptions drops field aliases and serializes inf/nan as null #2038

  2. How was this tested:
    New tests in tests/contrib/pydantic/test_pydantic.py:

  • test_to_json_options_wire_format_matches_default (parametrized): byte-for-byte parity between the converter with ToJsonOptions() / ToJsonOptions(exclude_unset=False) and the default converter for an alias model (alias, float, timedelta, bytes), inf, -inf, nan, [inf, 1.5, nan], {"ratio": inf} and a dict with timedelta and bytes.
  • test_to_json_options_exclude_unset_keeps_aliases: exclude_unset=True emits {"orderId":7} and round-trips.

On pydantic 2.14.1 the new tests fail without the change (7 failed, 32 passed) and tests/contrib/pydantic passes with it (39 passed). Also checked on pydantic 2.11.0 (new tests fail before, pass after) and 2.10.6 (only the inf/nan cases fail before). The reproduction from the issue now sends orderId=7 and the workflow sees 7. Not run: the other contrib suites and CI.

  1. Any docs updates needed?
    No. Changelog fragment added under changelog/fixed.

PydanticJSONPlainPayloadConverter serialized through
SchemaSerializer(any_schema()).to_json() when to_json_options was set.
Since pydantic 2.11 that path defaults to by_alias=False, and
ser_json_inf_nan defaults to 'null', unlike pydantic_core.to_json
(by_alias=True, inf/nan as constants). Aliases were dropped and inf/nan
became null whenever e.g. exclude_unset=True was used.

Pass by_alias=True and configure the serializer with
ser_json_inf_nan='constants' so the options only change what they control.
@avanish-garg
avanish-garg requested a review from a team as a code owner October 29, 2026 13:02
@tconley1428
tconley1428 merged commit df3dc84 into temporalio:main Oct 29, 2026
20 checks passed
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.

[Bug] Pydantic converter with ToJsonOptions drops field aliases and serializes inf/nan as null

2 participants