Skip to content

fix: Validate value before writing deferred name in JsonWriter#2999

Open
daguimu wants to merge 1 commit intogoogle:mainfrom
daguimu:fix/jsonwriter-nan-writes-name-issue1736
Open

fix: Validate value before writing deferred name in JsonWriter#2999
daguimu wants to merge 1 commit intogoogle:mainfrom
daguimu:fix/jsonwriter-nan-writes-name-issue1736

Conversation

@daguimu
Copy link
Copy Markdown

@daguimu daguimu commented Mar 26, 2026

Problem

When JsonWriter.value(float), value(double), or value(Number) is called with a non-finite value (NaN, Infinity) in non-lenient mode, the deferred property name is written to the output before the value is validated. The validation then throws an IllegalArgumentException, but the name has already been emitted, leaving the writer in an inconsistent state.

This is particularly problematic when serializeNulls is set to false: a subsequent nullValue() call intended to suppress the property will find the name already written.

Root Cause

In all three methods, writeDeferredName() was called before the NaN/Infinity validation check. The deferred name is a side-effecting write to the output stream that cannot be undone after the exception.

Fix

Move the validation checks before writeDeferredName() in all three methods:

  • value(float): move Float.isNaN/isInfinite check before writeDeferredName()
  • value(double): move Double.isNaN/isInfinite check before writeDeferredName()
  • value(Number): move the entire validation block (NaN/Infinity check and number format validation) before writeDeferredName()

Tests Added

  • testNonFiniteValueDoesNotWriteDeferredName — verifies that when serializeNulls=false:
    • value(Float.NaN) throws without writing the name, allowing nullValue() to suppress it
    • value(Double.NaN) throws without writing the name
    • value(Double.POSITIVE_INFINITY) throws without writing the name
    • value(Number) with Double.NaN throws without writing the name
    • value(Number) with invalid number string throws without writing the name
    • Final output is {} (empty object, all names suppressed)

Impact

Only affects the error path for non-finite values in non-lenient mode. Normal finite value writing is unchanged. All 4587 existing tests pass.

Fixes #1736

JsonWriter.value(float), value(double), and value(Number) called
writeDeferredName() before validating whether the value is finite.
This meant that if a NaN or Infinity value was rejected with an
exception, the property name had already been written to the output,
leaving the writer in an inconsistent state.

Move the validation before writeDeferredName() so that invalid values
are rejected without any side effects on the output.

Fixes google#1736
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.

Non-lenient JsonWriter.value for NaN or Infinity writes name before throwing exception

1 participant