Skip to content

fix: Serialize non-finite float values as protobuf JSON strings - #1278

Merged
stephenh merged 1 commit into
stephenh:mainfrom
ozenyunus35:fix/non-finite-float-json
Oct 11, 2026
Merged

stephenh merged 1 commit into
stephenh:mainfrom
ozenyunus35:fix/non-finite-float-json

Conversation

@ozenyunus35

Copy link
Copy Markdown
Contributor

Summary

Fixes #1260.

Serialize non-finite float and double values according to the protobuf JSON mapping.

Previously, generated toJSON methods returned NaN, Infinity, and -Infinity as JavaScript numbers. When passed through JSON.stringify, these values became null, causing data loss during JSON round trips.

With this change, non-finite values are serialized as the protobuf-defined strings:

  • NaN → "NaN"
  • Infinity → "Infinity"
  • -Infinity → "-Infinity"

Finite numbers retain their existing representation.

Implementation

  • Add a floating-point type predicate covering float, double, FloatValue, and DoubleValue.
  • Add a floatToJson helper that preserves finite and nullish values while converting non-finite numbers to their canonical string representations.
  • Apply the conversion across generated toJSON paths, including singular fields, repeated fields, maps, oneofs, and wrapper values.
  • Emit the helper only in generated files that need it.
  • Regenerate integration outputs using the repository's pinned protoc 3.19.1.

The generated-code changes account for most of the modified files. A control regeneration using the original source produced no diff, confirming that the regeneration process matches the repository's existing output.

Testing

Added an integration case under integration/non-finite-floats covering non-finite serialization across supported field shapes and JSON round trips.

Regression verification:

  • Before the fix: both new tests fail.
  • After the fix: both new tests pass.

Validation:

  • Full Jest suite: 139 test suites passed, 576 tests passed, 4 skipped.
  • TypeScript checks passed across all 5 projects.
  • Prettier checks passed for source and handwritten tests.
  • Generated integration files follow the repository's existing generated-code formatting.

Scope

This change addresses toJSON serialization.

A separate pre-existing limitation remains in fromJSON for maps containing wrapper values such as map<string, FloatValue>. Those values are not converted consistently, independently of this change. Fixing that broader wrapper-map parsing behavior is outside the scope of #1260.

AI Assistance

Claude Code assisted with implementation, test development, and local validation. The changes and test results were reviewed before submission.

The proto3 JSON mapping represents NaN, Infinity and -Infinity as the
strings "NaN", "Infinity" and "-Infinity", because JSON numbers cannot
hold them. toJSON returned the raw numbers instead, which
JSON.stringify turns into null, so these values were lost on a round
trip through JSON (fromJSON already accepts the string forms).

Write double and float fields, and their DoubleValue/FloatValue
wrappers, through a floatToJson helper. This covers single, repeated,
map and oneof fields.

Fixes stephenh#1260
// fromJSON does not convert the values of maps of wrapper types, so leave fwm out.
const roundTripped: Floats = { ...message, fwm: {} };
const json = JSON.parse(JSON.stringify(Floats.toJSON(roundTripped)));
expect(Floats.fromJSON(json)).toEqual(roundTripped);

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

Great test!

Comment thread src/main.ts
} else if (isWholeNumber(valueType) && !(isLong(valueType) && options.forceLong === LongOption.STRING)) {
return code`Math.round(${from})`;
} else if (isFloatingPoint(valueType)) {
return code`${utils.floatToJson}(${from})`;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This is great, very clean

@stephenh

Copy link
Copy Markdown
Owner

Appreciate the PRs @ozenyunus35 !

@stephenh
stephenh merged commit 8c45e89 into stephenh:main Oct 11, 2026
6 checks passed
stephenh pushed a commit that referenced this pull request Oct 11, 2026
## [2.13.3](v2.13.2...v2.13.3) (2026-10-11)

### Bug Fixes

* Serialize non-finite float values as protobuf JSON strings ([#1278](#1278)) ([8c45e89](8c45e89)), closes [#1260](#1260) [#1260](#1260)
@stephenh

Copy link
Copy Markdown
Owner

🎉 This PR is included in version 2.13.3 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

toJSON does not emit canonical JSON for non-finite double/float values, breaking round-trips through JSON.stringify

2 participants