← 전체 글

JSON 위치 0의 Unexpected Token u: undefined를 파싱

"Unexpected token u" 오류는 JSON.parse(undefined)를 호출했다는 뜻. undefined가 어떻게 "undefined"가 되는지, 어떻게 막을지, 안전한 파싱 헬퍼를 배운다.

SyntaxError: Unexpected token 'u', "undefined" is not valid JSON (구버전 엔진: Unexpected token u in JSON at position 0) 는 거의 항상 당신이 JSON.parse(undefined) 를 호출했다는 뜻입니다. JavaScript 는 undefined 를 텍스트 "undefined" 로 문자열화하고, 파서는 앞의 u 에 막힙니다. 이유와 고치는 법은 아래.

오류의 모습

// V8 (Chrome / Node / Edge)
SyntaxError: "undefined" is not valid JSON
SyntaxError: Unexpected token 'u', "undefined" is not valid JSON
SyntaxError: Unexpected token u in JSON at position 0   // 구버전 V8

// Firefox
SyntaxError: JSON.parse: unexpected character at line 1 column 1

// Safari
SyntaxError: JSON Parse error: Unexpected identifier "undefined"

위치 0 의 u 는 문자열 "undefined" 의 첫 글자 —— 파서는 실제 데이터를 받지 못한 것입니다.

왜 일어나는가: undefined 를 파싱했음

JSON.parse() 는 인수를 먼저 문자열로 강제 변환합니다. undefined 를 넘기면 리터럴 텍스트 "undefined" 를 파싱하는데, 이는 유효한 JSON 이 아닙니다. 값이 보통 undefined 인 이유:

  • 변수나 함수 인수가 한 번도 할당되지 않음
  • 객체 속성이 존재하지 않음 (오타 또는 구조 차이): obj.missing
  • async 값이 아직 준비되지 않음 (await 전에 파싱)
  • return 이 없는 함수를 소스로 사용

고장 난 예제

const cached = localStorage.getItem('settings'); // 키 누락 → null, OK
const draft  = window.appState?.draft;            // 속성 누락 → undefined
const data   = JSON.parse(draft);                 // ❌ "undefined" is not valid JSON

고친 예제

// 파싱 전에 가드
const data = draft ? JSON.parse(draft) : null;

// 또는 안전한 helper
function safeParse(text, fallback = null) {
  if (typeof text !== 'string' || text.trim() === '') return fallback;
  try { return JSON.parse(text); } catch { return fallback; }
}
const data2 = safeParse(draft);

참고: JSON.parse(null)던지지 않습니다 —— null 을 반환합니다 —— 그리고 localStorage.getItem() 은 누락된 키에 null 을 반환합니다 (undefined 이 아님). 그래서 u 오류는 명확히 undefined 값을 가리키지, 누락된 스토리지 키가 아닙니다.

SyntaxError vs TypeError: 왜 이쪽 이 나오는가

미묘하지만 유용한 디테일: JSON.parse(undefined)SyntaxError 를 던집니다, TypeError 가 아닙니다. 왜? 명세상 JSON.parse 는 먼저 인수를 문자열로 강제 ("undefined") 한 다음 그 문자열을 파싱합니다. 오류는 "이 문자열은 유효한 JSON 이 아니다" 이지 "잘못된 타입을 넘겼다" 가 아닙니다. 그래서 JSON.parse(undefined)JSON.parse("undefined") 가 동일한 "position 0" 메시지를 냅니다.

타입 체크를 정말 하는 API 들과 대조하세요: JSON.stringify(BigInt(1))TypeError, 또는 JSON.parse(Symbol())TypeError (Symbol 은 문자열로 강제할 수 없음). 파싱 오류를 catch 할 거라면 err instanceof SyntaxError 로 좁혀서 나쁜 데이터나쁜 인수 를 따로 처리하세요.

고치는 법 —— 단계별로

  1. 입력을 로그하세요:console.log(typeof src, src) 를 파싱 바로 앞에 둡니다. undefined 가 찍히면 그게 범인입니다.
  2. 설정되어야 할 곳을 추적 —— 초기화되지 않은 state 필드, 빠진 인수, 또는 객체에 존재하지 않는 속성.
  3. 가드를 추가 (if (src)) 또는 safeParse 폴백, 누락된 값이 JSON.parse() 에 도달하지 못하게.
  4. async 라면, 파싱 전에 값을 await 했는지 확인하세요.

자주 묻는 질문

"Unexpected token u in JSON at position 0" 가 뭔가요?

undefinedJSON.parse() 에 넘겼습니다. 문자열 "undefined" 가 되고, 앞의 u 는 유효한 JSON 시작 문자가 아닙니다.

"token o" 나 "token <" 오류와 같은 건가요?

같은 패밀리, 다른 값. u = undefined; token o = 객체가 [object Object] 로 문자열화됨; token < = HTML 응답. 명시된 문자가 실제로 넘긴 게 무엇인지 알려 줍니다.

왜 JSON.parse(null) 은 같은 오류를 안 내나요?

"null" 은 유효한 JSON 이라 JSON.parse(null)null 을 반환합니다. undefined (→ "undefined") 만이 u 오류를 일으킵니다.

지금 바로 고치기