Skip to content

fix: sanitize NaN/Infinity to null in serialize_json#43

Draft
saksharthakkar wants to merge 1 commit intomainfrom
fix/sanitize-nan-infinity-json
Draft

fix: sanitize NaN/Infinity to null in serialize_json#43
saksharthakkar wants to merge 1 commit intomainfrom
fix/sanitize-nan-infinity-json

Conversation

@saksharthakkar
Copy link

@saksharthakkar saksharthakkar commented Feb 17, 2026

Summary

  • Add _sanitize_nan() to recursively replace float('nan'), float('inf'), float('-inf') with None before JSON serialization
  • Add allow_nan=False to json.dumps() as defense-in-depth
  • Export _sanitize_nan for use by downstream packages (e.g., uipath-tracing exporter)

Root Cause (AE-1026)

The .NET backend returns "Unexpected character encountered while parsing value" (OPS0006). This specific Newtonsoft.Json error means it hit an unexpected token like N or I where it expected a JSON value — ruling out the ticket's stated cause of "special characters (backslashes, quotes, newlines)" which json.dumps() handles correctly.

The only case where Python's json.dumps() produces invalid JSON is NaN/Infinity floats — it outputs bare tokens (NaN, Infinity) that violate RFC 8259 §6. These survive the full serialization chain: serialize_json()_safe_parse_json() (Python's json.loads accepts NaN) → re-serialized via json.dumps(attributes_dict)Attributes string hits .NET parser → failure. The intermittent nature (5 failures, 3 orgs) matches: only agent runs with tool outputs containing NaN floats (data processing, division-by-zero) trigger it.

Approach

Recursive NaN → null sanitization before json.dumps() is industry-standard (e.g., pandas, Redash, orjson, pydantic v2, Datadog, Sentry all do the same). Custom JSONEncoder.default() does NOT work for floats since they're natively serializable, so the recursive walk is necessary.

Test plan

  • NaN, +Infinity, -Infinity all serialize to null
  • Normal floats preserved
  • Nested NaN in dicts, lists, deeply nested structures
  • Output is valid JSON (parseable by strict parsers)
  • Non-float types unchanged
  • All 47 existing + new tests pass

🤖 Generated with Claude Code

…pliance

Python's json.dumps() outputs bare NaN/Infinity tokens which violate RFC 8259.
Strict JSON parsers (.NET, Go, Rust) reject these, causing OPS0006 errors in
UpsertSpan/ShellReportStart when span attributes contain non-finite floats.

Add _sanitize_nan() recursive walk before json.dumps() to convert NaN/Infinity
to None (null), plus allow_nan=False as defense-in-depth. This matches the
pattern used by orjson, pydantic, pandas, Datadog, and Sentry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments