Skip to content

Keep floats in int and float unions when decoding typed JSON payloads - #1958

Closed
LindseyZ1205 wants to merge 1 commit into
temporalio:mainfrom
LindseyZ1205:fix/union-int-float
Closed

LindseyZ1205 wants to merge 1 commit into
temporalio:mainfrom
LindseyZ1205:fix/union-int-float

Conversation

@LindseyZ1205

Copy link
Copy Markdown
Contributor

value_to_type tries the members of a union in order, and the int conversion accepts a float and truncates it. So with a type hint such as int | float, a float is decoded as an int:

from dataclasses import dataclass

from temporalio.converter import JSONPlainPayloadConverter


@dataclass
class Price:
    amount: int | float


converter = JSONPlainPayloadConverter()
converter.from_payload(converter.to_payload(Price(9.99)), Price)
# Price(amount=9)

The same happens for int | float | None, list[int | float] and dict values. When the union has a float member and the value is a float, convert it as a float before trying the other members. A plain int hint still truncates, as ok(int, 5.5, 5) in test_json_type_hints expects, and an int value in an int | float union is still an int.

I found this by reading value_to_type, not in a production workflow.

Validation on Python 3.12.13:

  • The new cases in test_json_type_hints fail before the fix (assert 5 == 5.5) and pass after it.
  • tests/test_converter.py and tests/test_common.py: 49 tests pass.
  • Ruff import/format checks, Pyright, BasedPyright and mypy report no issues for the changed files; pydocstyle passes for the changed source file.
  • Tested with the current Python source and the unmodified Rust bridge from the temporalio 1.33.0 wheel. I did not run server-backed tests, the full repository lint, or other Python versions.

AI disclosure: I used Claude Code to find this bug and write the fix and the tests. I reviewed the change and ran the tests locally.

🤖 Generated with Claude Code

value_to_type tries the members of a union in order, and the int
conversion accepts a float and truncates it. So a float decoded with a
type hint such as int | float became an int: 9.99 became 9, also in
dataclass fields, lists and dict values. When the union has a float
member and the value is a float, convert it as a float. A plain int
hint still truncates, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@LindseyZ1205
LindseyZ1205 requested a review from a team as a code owner October 11, 2026 18:03
@tconley1428

Copy link
Copy Markdown
Contributor

Generally we would recommend using the pydantic_data_converter if you hit the limitations of the built in one, which will never be fully robust. Given that this could potentially be backwards incompatible, and that there isn't a real use case being blocked, closing.

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