⚡ The Object Property That Disappeared on the Way to JSON
JSON has no representation for undefined, functions, or symbols – the format simply doesn’t define a way to encode them – so JSON.stringify doesn’t throw or warn when it encounters one, it just leaves the corresponding key out of the output entirely. A property that’s clearly present on the object, readable with dot notation and visible in a console.log, can vanish completely the moment that same object goes through JSON.stringify, with the resulting string looking shorter and the receiving end seeing a payload with fewer fields than the sender believed it sent.
🔎 The Problem
const payload = {
orderId: 42,
total: 99.99,
discountCode: undefined, // will be dropped entirely
calculateTax: () => 0.08, // will be dropped entirely
[Symbol('internal')]: 'x', // will be dropped entirely
};
console.log(payload);
// { orderId: 42, total: 99.99, discountCode: undefined, calculateTax: f, Symbol(internal): 'x' }
// Every property is visibly right there.
const json = JSON.stringify(payload);
console.log(json);
// '{"orderId":42,"total":99.99}'
// discountCode, calculateTax, and the symbol key are all just gone -
// not null, not an error, simply absent from the string.
✅ Fix: Normalize Values Before Serializing, and Check the Serialized Output Directly
- Replace undefined with null (or a real default value) before serializing anything that needs to preserve the key – null does have a JSON representation and will survive the round trip.
- Never assume an object’s in-memory shape matches its serialized shape – inspect the actual output of JSON.stringify(obj) when debugging a ‘missing field’ issue on the receiving end, instead of only checking the object before it was serialized.
- If a function’s result needs to travel with the payload, call it and store its return value in a plain property beforehand – JSON.stringify can’t serialize behavior, only data, no matter how the object is structured.
⚠️ Why This Is Easy to Miss
- console.log(payload) and JSON.stringify(payload) can show two visibly different sets of properties for the exact same object, and it’s easy to debug by eye on the first one without ever directly inspecting the second.
- The silence is total – no warning in the console, no error thrown, no indication at serialization time that anything was left out – so the first sign of trouble is usually a confused ‘why is this field missing?’ on a completely different service that only ever sees the JSON.
JSON.stringify doesn’t refuse what it can’t represent – it just leaves it out, as if you’d never written it at all.
