Skip to content

JSON.stringify of boxed primitive wrappers (new String/Number/Boolean) returns {} instead of the primitive #3857

Closed

Description

@proggeramlug

Summary

JSON.stringify of a boxed primitive wrapper (new String(x) / new Number(x)
/ new Boolean(x)) returns {} instead of serializing via the wrapped primitive
value. Per spec, JSON.stringify calls the wrapper's internal [[StringData]] /
[[NumberData]] / [[BooleanData]] (via toJSON/coercion), so a String wrapper
serializes as the JSON string, a Number wrapper as the number, etc.

Reproduction

console.log(JSON.stringify(new String("T")));   // Perry: {}   Node: "T"
console.log(JSON.stringify(new Number(42)));     // Perry: {}   Node: 42
console.log(JSON.stringify(new Boolean(true)));  // Perry: {}   Node: true

// Also surfaces via a primitive `this` (sloppy-mode boxing), e.g.
function f(this: any) { return this; }
console.log(JSON.stringify(f.apply("T", [])));   // Perry: [... {} ...]  Node: "T"

typeof already agrees ("object" for the wrapper in both), so the boxing itself
is correct — only the JSON.stringify serialization path doesn't unwrap.

A primitive this value passed to Function.prototype.apply/call is boxed to such
a wrapper (sloppy mode), so this is the residual difference in the #3828 minimal
repros that use a string thisArg (f.apply("T", [1,2])). It is independent of
call/apply/bind dispatch — it reproduces with new String("T") directly.

Notes

Found while fixing #3828 (PR #3856). The call/apply/bind dispatch itself is correct;
this is purely the JSON serializer not unwrapping boxed primitive wrapper objects.

Activity

  1. proggeramlug commented on Jun 1, 2026

    @proggeramlug
    ContributorAuthor

    Fixed in #3972 (merged to main as 4eede44, v0.5.1058). Verified byte-for-byte against node --experimental-strip-types with a node-suite regression fixture.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions