ErrLookupBackground articles › "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them

"JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them

JSON serialization failed, "Value is not JSON serializable", "Failed to serialize object", and similar marshaling errors appear when a library tries to convert an in-memory value into JSON and encounters something the JSON data model cannot represent: circular references, NaN or Infinity floats, BigInt, Date/Map/class instances, functions, symbols, or channels. This page explains the common mechanics behind these errors across Rust (serde_json), Go (encoding/json), JavaScript (JSON.stringify), Java (Jackson), and Python (pandas), and how to find and fix the offending value.

Distilled from 101 documented records across 46 repositories.

Background

These errors all come from the moment a value is converted into JSON bytes — the marshal step in serde_json (Rust), encoding/json (Go), JSON.stringify (JavaScript), Jackson (Java), or pandas' to_json (Python). The JSON data model only permits null, booleans, numbers, strings, arrays, and objects with string keys. Every library in this family wraps that conversion, but the fundamental failure modes are the same: a value of an unsupported type (a Go channel or func, a JS function or symbol, a Python set or numpy scalar), a value outside JSON's number model (NaN/Infinity in serde_json and encoding/json), or a structural problem like a circular reference. The error text varies — 'JSON serialization failed', 'Value is not JSON serializable', 'Cannot serialize field X into JSON', 'failed to marshal current netmap' — but the mechanism is identical.

An important pattern across the records: many of these errors are internal invariant guards that are essentially unreachable in released software. serde_json's to_string over a plain Value cannot fail except on non-finite floats or map-length overflow; the llmfit codebase documents its .expect("JSON serialization failed") as an internal invariant per its own conventions, and k6's 'marshaling hosts option' and Windmill's decimal conversion are similar defensive branches. When you hit one of these in an unmodified build, the message usually indicates an internal regression or corrupt state rather than user error — the llmfit, k6, tailscale, pnpm, and SiYuan records all say a reproducible case is a bug to report upstream. By contrast, errors at genuine data boundaries (Electron IPC payloads, MLflow log_table, page.evaluate arguments, durable session logs) are user-fixable: the payload genuinely contained something JSON cannot express.

The caller's experience splits by how the library reports failure. Some fail fast with a precise reason: pi's assertJsonSerializable names the exact violation (circular reference, NaN, sparse array, accessor property), OpenCLI's evaluate error points to the offending argument position, and pulumi/mlflow wrap the underlying encoder error so the %w or inner cause identifies the failing type. Others deliberately swallow the cause — Hadoop's 'Cannot serialize field X into JSON' rethrows with only the field name, so diagnosis depends on inspecting that field's type. Still others surface the failure confusingly late or as a different error class entirely: geektutu's gee framework writes the raw marshal error as an HTTP 500 body, tailscale returns HTTP 500 from a debug endpoint, and deno's Response.json throws a TypeError only when the top-level value is undefined, a function, or a symbol — nested bad values are silently dropped instead.

Two number-related quirks are worth knowing because they vary by library. Non-finite floats are an error in serde_json ('float must be finite' — the trigger behind NaN scores reaching llmfit's JSON output) and in Go's encoding/json, but JavaScript's JSON.stringify converts NaN/Infinity to null and pandas' to_json may raise instead, so the same NaN value is fatal in one stack and silently coerced in another. Precision loss is handled differently too: Windmill explicitly does not fail on a NUMERIC that merely loses precision past ~15-17 significant digits — it flags it and returns a rounded number — and only fails when the value is entirely outside f64 range, such as a 1e+1000000000 exponent.

Common causes

What usually fixes it

Go deeper

Documented occurrences

…and 81 more across the corpus — use search.

Honest provenance: generated on 2026-09-05 from AI-assisted analysis of the linked records. See how records are made.