V8 Node v24.15.0, V8 13.6.233.17에서 파서를 실행해 확인했습니다.
"undefined" is not valid JSON
JSON.parse에 undefined를 넘겼습니다. 그것은 문자열 "undefined"로 바뀌고, JSON에는 그런 리터럴이 없어서 0번 위치에서 실패합니다. 진짜 질문은 그 undefined가 어디서 왔느냐이고, 답은 대략 셋뿐입니다.
이렇게 적힌 것을 보게 될 수도 있습니다
- Unexpected token u in JSON at position 0
V8은 2022년에 JSON 오류 메시지 대부분을 다시 썼습니다. 검색 결과에 나오는 건 여전히 옛 문구가 대부분이지만, 지금의 어떤 런타임도 그 문구를 내보내지 않습니다.
JSON을 붙여넣고 어디서 깨지는지 정확히 확인하기
입력
붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기
실제 원인
어느 쪽이 답인 경우가 많은지, 그 순서대로 정리했습니다.
-
01 한 번도 설정된 적 없는 스토리지 키
localStorage.getItem은 없는 키에 대해 null을 돌려주고, JSON.parse(null)은 실제로 동작합니다. 하지만 그 키에 문자열 "undefined"가 한 번이라도 기록됐다면, 다시 읽을 때마다 정확히 이 오류가 납니다. 키를 지울 때까지 계속입니다.
깨지는 예
localStorage.setItem('token', someUndefinedValue); // writes "undefined" JSON.parse(localStorage.getItem('token'));되는 예
const raw = localStorage.getItem('token'); const token = raw && raw !== 'undefined' ? JSON.parse(raw) : null; -
02 비동기 값을 기다리지 않음
프로미스에서, 또는 아직 로드되지 않은 상태에서 속성을 읽으면 undefined가 됩니다. 데이터가 도착하기 전에 파싱이 실행된 것입니다.
깨지는 예
const data = JSON.parse(fetchUser().body);되는 예
const res = await fetchUser(); const data = JSON.parse(await res.text()); -
03 존재하지 않는 속성
이름이 바뀐 필드, 오타, 또는 형태가 달라진 API. 페이로드가 obj.result를 쓰는데 obj.data를 읽으면 다른 경고 하나 없이 undefined가 나옵니다.
자주 묻는 질문
- 왜 JSON.parse(null)은 되는데 JSON.parse(undefined)는 안 되나요?
- 둘 다 먼저 문자열로 바뀝니다. null은 "null"이 되는데 이건 유효한 JSON 문서라 파싱되어 null을 돌려줍니다. undefined는 "undefined"가 되고, JSON에는 그에 해당하는 리터럴이 없습니다.
- 문자열 "undefined"가 든 키는 어떻게 지우나요?
- localStorage.removeItem(키)를 쓰거나, 위에 보인 것처럼 읽는 쪽을 방어하세요. 잘못된 값은 새로고침을 넘겨서도 남기 때문에, 이 오류는 기기마다 나타났다 안 났다 하는 것처럼 보이곤 합니다.