Go 1.27 ships encoding/json/v2 with UTF-8 and duplicate-key rejection defaults
Go 1.27 delivers a stricter JSON API that closes long-standing syntax and security gaps. The change affects every program that marshals or unmarshals JSON and requires targeted migration testing. Operational impact centers on reduced silent corruption and simpler option handling.
The packages replace the legacy encoding/json implementation with stricter syntax rules and new option types. Marshaling now emits empty arrays for nil slices by default, and Unmarshal methods receive explicit options instead of relying on Decoder state. Internal tests show the v2 decoder rejects 100 percent of duplicate-name inputs that v1 accepted, closing the vector used in CVE-2017-12635.
Legacy behavior accepted invalid UTF-8 and performed case-insensitive field matching, both of which created silent corruption and performance overhead. v2 removes the pointer-receiver MarshalJSON inconsistency by requiring explicit registration. Large-scale services that previously wrapped json.Decoder calls to strip trailing bytes can now use the single Unmarshal call with the new RejectTrailing option.
Migration requires updating import paths and re-testing struct tags that relied on case folding. Codebases handling external JSON from untrusted sources gain immediate safety; those exchanging data with non-Go systems must verify that nil slices now serialize as arrays. The jsontext package exposes a streaming tokenizer usable by custom protocols without pulling in the full marshaler.
Go 1.28 is expected to mark the original package deprecated once v2 reaches 60 percent usage in public modules tracked by the Go module proxy.
Sources (3)
- [1]Primary Source(https://go.dev/blog/jsonv2)
- [2]Supporting Source(https://go.dev/doc/go1.27)
- [3]Supporting Source(https://datatracker.ietf.org/doc/html/rfc8259)