JSON.stringify() 필드 누락 오류 해결법 (undefined와 null 차이)

JSON.stringify()는 객체 속성의 값이 undefined이면 그 속성을 결과 JSON에서 뺍니다. null은 그대로 남습니다. 데이터를 JSON으로 바꾼 뒤 필드가 빠졌다면, 변환 전 값과 변환 후 키의 존재를 따로 확인하세요.

AI가 만든 JavaScript 코드에서도 원본 객체에 보이던 필드가 JSON 문자열에서는 없어질 수 있습니다. 값이 undefined로 읽힌다는 사실만으로 두 객체의 구조가 같다고 볼 수는 없습니다.

값은 둘 다 undefined인데, 키는 한쪽에만 있습니다

실제 서비스 데이터가 아닌 작은 합성 객체를 JSON으로 바꾼 뒤 다시 읽었습니다.

const before = { name: "sample", note: undefined };
const text = JSON.stringify(before);
const after = JSON.parse(text);

console.log(text); // {"name":"sample"}
console.log(before.note === undefined); // true
console.log(after.note === undefined);  // true
console.log(Object.hasOwn(before, "note")); // true
console.log(Object.hasOwn(after, "note"));  // false

before에는 note라는 속성이 있고 값이 undefined입니다. after에는 note 속성 자체가 없습니다. 그런데 두 객체에서 note를 읽으면 둘 다 undefined가 나옵니다. 마지막 두 줄처럼 속성의 존재까지 봐야 누락을 구별할 수 있습니다.

MDN의 Object.hasOwn 설명은 값이 null이나 undefined여도 객체에 직접 정의된 속성이 있으면 true를 반환한다고 명시합니다. 이 예제의 false는 ‘빈 값이 유지됐다’가 아니라 ‘그 키가 없다’는 결과입니다.

종이 봉투 속 문서의 빈 필드 자리와 밖에 놓인 undefined 탭
undefined 속성이 JSON에서 빠지는 상황을 표현한 생성 일러스트입니다. 실제 요청 화면은 아닙니다.

객체 속성, 배열 요소, 최상위 값은 다르게 처리됩니다

undefined가 들어갔다고 언제나 같은 모양의 결과가 나오는 것은 아닙니다. MDN의 JSON.stringify 설명에 따르면 객체 속성의 undefined는 빠지고, 배열 안의 undefined는 null로 바뀝니다. 최상위 값 자체가 undefined라면 JSON 문자열이 아니라 JavaScript의 undefined를 반환할 수 있습니다.

console.log(JSON.stringify({ note: undefined })); // {}
console.log(JSON.stringify([undefined]));        // [null]
console.log(JSON.stringify(undefined) === undefined); // true
console.log(JSON.stringify({ note: null })); // {"note":null}

첫 줄은 note 속성이 빠진 객체의 JSON입니다. 두 번째 줄은 배열의 해당 위치가 null로 남습니다. 세 번째 줄의 true는 반환값이 문자열 "undefined"가 아니라 실제 undefined라는 뜻입니다. null을 넣은 마지막 객체에는 note 키가 유지됩니다.

이 글의 예제는 평범한 객체의 직접 정의된 열거 가능한 문자열 키와 작은 배열을 사용합니다. 사용자 정의 toJSON이나 별도 replacer가 개입한 변환까지 같은 결과라고 넓히지 않습니다.

객체 폴더와 null 표시가 남은 배열 리본, 최상위 undefined 종이
객체·배열·최상위 값의 처리가 다름을 표현한 생성 그림입니다. 정확한 출력은 본문 코드를 따릅니다.

필드를 남기려고 null로 바꾸기 전에 의미부터 정하세요

‘이 필드를 보내지 않음’과 ‘이 필드에 null을 보냄’은 같은 데이터가 아닙니다. 서버가 두 경우를 어떻게 처리하는지는 해당 API의 계약을 확인해야 합니다. null을 보냈다는 이유만으로 저장된 값이 삭제되거나 초기화된다고 단정할 수 없습니다.

아래는 undefined를 null로 바꿔 직렬화하는 합성 예제입니다. 네트워크 요청이나 서버 동작을 시험한 코드는 아닙니다.

const value = { name: "sample", note: undefined };
const textWithNull = JSON.stringify(value, (key, current) => {
  return current === undefined ? null : current;
});

console.log(textWithNull); // {"name":"sample","note":null}
console.log(value.note === undefined); // true

JSON.stringify의 replacer 매개변수는 직렬화할 값을 바꿀 수 있습니다. 이 코드에서는 JSON 문자열에 null이 남지만, 원본 value.note는 여전히 undefined입니다. 원본 속성을 수정하는 코드와도 구분해야 합니다.

원래부터 note: null을 만들기로 합의했다면 그 값을 명시하는 편이 의도를 드러냅니다. 반대로 수신 측에서 null을 받지 않는 필드라면, 누락을 막으려고 일괄 치환하는 것은 해결책이 아닙니다.

키가 없는 책의 빈 탭 자리와 null 탭이 남아 있는 책
키가 없는 상태와 null 값이 있는 상태를 구분한 개념 그림입니다. 생성 일러스트입니다.

AI에게 고쳐 달라고 할 때는 키가 남아야 하는지도 적으세요

‘빈 값을 고쳐줘’ 대신 원하는 데이터의 모양을 구체적으로 주세요. 예를 들어 ‘note를 생략하는 경우와 note: null을 보내는 경우를 나누고, 직렬화된 문자열을 출력해 줘. 서버 처리는 가정하지 마’라고 요청할 수 있습니다. 설명용 요청문이며, 모든 AI가 이 조건을 정확히 지킨다는 보장은 아닙니다.

코드를 확인할 때도 원본 객체만 보지 말고 실제로 만든 JSON 문자열을 함께 읽으세요. 값을 읽는 검사와 키의 존재를 확인하는 검사를 나눠 두면, ‘비어 있음’과 ‘누락’을 혼동할 여지가 줄어듭니다.

반대로 JSON을 읽는 데 성공했는데 안의 자료형이나 계산이 틀렸다면 다른 문제입니다. JSON.parse 성공과 합계 검사를 구분한 예제로 이어서 확인할 수 있습니다.

출처 및 확인일

문서·실행 확인: 2026년 11월 1일 KST. Windows x64의 Node.js 26.5.0(V8 14.6.202.34-node.24)에서 본문 코드 3블록을 그대로 실행해 출력과 속성 존재 차이를 확인했습니다. 이미지는 실제 UI나 실행 결과가 아닌 설명용 생성 일러스트입니다.