가이드

developer

JSON 파싱 오류 원인 7가지와 고치는 법 (RFC 8259 기준)

Unexpected token 오류가 나는 진짜 이유. 끝의 쉼표, 작은따옴표, 주석, 숫자 형식, 한글 이스케이프까지 JSON 표준 문법과 자주 하는 실수를 예시로 정리합니다.

modu.tools Editorial · ·

API 응답을 붙여 넣거나 설정 파일을 고치다 보면 Unexpected token, Expected property name 같은 오류를 자주 만납니다. JSON은 문법이 아주 작은 형식이라, 오류의 원인도 대개 몇 가지로 정해져 있습니다. 이 글은 JSON의 표준 문서인 RFC 8259를 바탕으로 문법을 짧게 정리하고, 실무에서 가장 자주 보는 실수 일곱 가지를 고치는 방법을 보여 드립니다.

JSON 문법 한눈에 보기

RFC 8259에 따르면 JSON 값은 여섯 가지 중 하나입니다.

종류 예시 비고
객체 {"이름": "모두"} 이름은 반드시 문자열
배열 [1, 2, 3] 순서 있는 값의 목록
문자열 "안녕" 큰따옴표만 허용
숫자 3.14, -2, 1e10 앞자리 0, NaN, Infinity 불가
불리언 true, false 소문자만
null null 소문자만

이것이 전부입니다. 날짜, 주석, 함수, undefined 같은 것은 없습니다. 또한 RFC 8259는 시스템 사이에 주고받는 JSON 텍스트는 UTF-8로 인코딩해야 한다고 규정합니다.

실수 1: 마지막 요소 뒤의 쉼표

{
  "name": "modu",
  "tools": 13,
}

JavaScript 객체에서는 마지막 쉼표(trailing comma)가 허용되지만 JSON에서는 오류입니다. 배열 [1, 2, 3,]도 마찬가지예요. 코드를 복사해 JSON으로 쓸 때 가장 흔하게 생기는 문제입니다. 마지막 쉼표를 지우면 해결됩니다.

실수 2: 작은따옴표

{'name': 'modu'}

JSON 문자열과 객체 이름은 큰따옴표만 쓸 수 있습니다. Python의 print(dict) 결과를 그대로 복사하면 작은따옴표가 들어가서 이 오류가 납니다. Python에서는 print() 대신 json.dumps()로 출력해야 올바른 JSON이 나옵니다. 같은 이유로 Python의 True, False, None도 JSON에서는 true, false, null이어야 합니다.

실수 3: 따옴표 없는 이름

{name: "modu"}

JavaScript에서는 name처럼 따옴표 없이 속성 이름을 쓸 수 있지만, JSON에서는 모든 이름이 문자열이어야 합니다. {"name": "modu"}로 고칩니다.

실수 4: 주석

{
  // 서버 포트
  "port": 8080
}

JSON에는 주석 문법이 없습니다. //나 /* */가 들어가면 표준 파서는 오류를 냅니다. 설정 파일에 설명이 필요하다면 "_comment": "서버 포트" 같은 별도 필드를 두거나, 주석을 지원하는 JSONC, JSON5, YAML 같은 형식을 쓰는 것을 검토하세요. 일부 도구(예: 코드 편집기의 설정 파일)는 주석을 허용하지만 그것은 그 도구의 확장 기능입니다.

실수 5: 숫자 형식

JSON 숫자는 생각보다 엄격합니다.

  • 007 → 앞자리 0은 허용되지 않습니다. 문자열 "007"로 쓰세요.
  • .5 → 소수점 앞에 0이 있어야 합니다. 0.5
  • +1 → 앞의 플러스 기호는 허용되지 않습니다.
  • NaN, Infinity → JSON 숫자가 아닙니다. 보통 null로 바꿉니다.
  • 0x1F → 16진수 표기는 없습니다.

또 하나 주의할 점은 정밀도입니다. RFC 8259는 숫자 정밀도를 제한하지 않지만, 많은 구현이 IEEE 754 배정밀도 부동소수점을 쓴다고 지적합니다. JavaScript에서 2^53(9007199254740992)보다 큰 정수는 정확하게 표현되지 않습니다. 주문번호나 트윗 ID처럼 큰 정수 ID는 문자열로 주고받는 것이 안전합니다.

실수 6: 문자열 안의 줄바꿈과 특수 문자

JSON 문자열 안에는 줄바꿈이나 탭 같은 제어 문자를 그대로 넣을 수 없습니다. 반드시 이스케이프해야 합니다.

문자 이스케이프
큰따옴표 \"
역슬래시 \\
줄바꿈 \n
탭 \t
기타 제어 문자 \u0000 형식

윈도 경로를 JSON에 넣을 때 "C:\Users\modu"처럼 쓰면 \U, \m이 잘못된 이스케이프가 되어 오류가 납니다. "C:\\Users\\modu"로 역슬래시를 두 번 써야 합니다.

실수 7: 한글이 \uXXXX로 보이는 경우

이것은 오류가 아니지만 자주 받는 질문입니다. 어떤 JSON은 한글이 "\uc548\ub155"처럼 보입니다. 이는 ’안녕’을 유니코드 이스케이프로 쓴 것으로, 완전히 올바른 JSON이며 파싱하면 ’안녕’이 됩니다. Python의 json.dumps()는 기본값으로 ASCII 이외의 문자를 이스케이프하는데, ensure_ascii=False를 주면 한글이 그대로 출력됩니다. 사람이 읽을 파일이라면 한글 그대로가 편하고, 인코딩이 불확실한 환경으로 보낼 때는 이스케이프가 안전합니다.

이모지처럼 U+FFFF보다 큰 문자는 서로게이트 쌍 두 개로 이스케이프됩니다. 😀는 "\ud83d\ude00"입니다.

오류 메시지 읽는 법

파서 오류에는 보통 위치(줄, 열, 또는 문자 위치)가 나옵니다. 그런데 표시된 위치는 문제가 감지된 곳이지 실수한 곳이 아닐 때가 많습니다. 예를 들어 닫는 중괄호가 빠진 경우 파일 맨 끝에서 오류가 납니다. 표시된 위치에서 문제가 안 보이면 바로 앞 줄들의 쉼표, 따옴표, 괄호 짝을 확인하세요.

중복된 이름은?

{"a": 1, "a": 2}처럼 같은 이름이 두 번 나오면 어떻게 될까요? RFC 8259는 객체 안의 이름이 고유**해야 한다(SHOULD)**고 권고하며, 중복될 경우 동작은 구현마다 다르다고 설명합니다. 대부분은 마지막 값을 쓰지만 오류를 내는 파서도 있습니다. 데이터를 만드는 쪽에서 중복을 피하는 것이 정답입니다.

modu.tools의 데이터 워크벤치에 JSON을 붙여 넣으면 오류 위치를 표시하고 보기 좋게 정렬해 줍니다. 모든 처리는 브라우저 안에서 이뤄집니다. CSV와 주고받을 때 주의할 점은 CSV 인코딩 가이드에 정리했습니다.

실수 8: 트레일링 데이터가 남는 경우

{"a":1}{"b":2}처럼 JSON 값 뒤에 또 다른 값이 이어지면, 많은 파서는 “Unexpected non-whitespace character after JSON” 같은 오류를 냅니다. 로그를 이어 붙인 NDJSON(한 줄에 JSON 하나)을 일반 JSON.parse에 통째로 넣은 경우에 흔합니다. 한 줄씩 나누어 파싱하거나, 처음부터 배열 [...]로 감싸야 합니다.

반대로 앞뒤에 설명 문장이 붙은 경우도 있습니다. 챗봇이나 문서에서 복사할 때 여기 JSON입니다: 같은 접두어가 함께 오면 파서가 첫 글자부터 실패합니다. 중괄호나 대괄호가 시작하는 지점부터 끝나는 지점까지만 잘라 내세요.

워크드 예시: 오류 위치 추적

잘못된 입력:

{
  "name": "모듈",
  "tags": ["csv", "json",],
  "ok": true
}
  1. 파서가 가리키는 위치는 보통 "ok" 근처나 ] 뒤입니다.
  2. 그 줄 자체가 아니라 바로 위의 ["csv", "json",]에서 마지막 쉼표를 찾습니다.
  3. 쉼표를 제거한 뒤 다시 파싱하면 통과합니다.

작은따옴표 버전:

{'name': '모듈'}

오류 메시지는 “Unexpected token ’” 형태인 경우가 많습니다. 키와 문자열을 모두 큰따옴표로 바꾼 뒤 재시도하세요. JavaScript 객체 리터럴과 JSON을 같은 문법으로 생각하면 이 지점에서 자주 넘어집니다.

큰 숫자와 정밀도

JSON 숫자는 대부분 IEEE 754 배정밀도로 읽힙니다. 정수로 안전하게 다루려면 대략 ±2^53−1(9,007,199,254,740,991) 안이어야 합니다. 주문번호·카드번호·64비트 정수 ID는 문자열로 넣는 편이 안전합니다.

값 JSON에 숫자로 넣으면 권장
9007199254740993 엔진에 따라 반올림될 수 있음 문자열
01012345678 앞자리 0 소실 + 숫자로 해석 문자열
1.0 1로 정규화되는 파서도 있음 필요하면 문자열

검증·포맷 워크플로

  1. 원본을 그대로 붙여 넣어 검증부터 한다.
  2. 오류 위치 주변 5~10줄을 읽는다(표시 위치 ≠ 원인 위치).
  3. 통과하면 들여쓰기 포맷으로 가독성을 확보한다.
  4. 키 정렬이 필요한 비교(diff)라면 정렬 옵션을 쓴다.
  5. 압축(minify)은 전송·저장 직전에만 수행한다.

modu.tools의 JSON 포매터와 워크벤치는 위 순서를 브라우저 안에서 반복할 때 유용합니다. 민감한 운영 설정값은 예제용으로만 다루세요.

자주 묻는 질문

JSON 최상위에 문자열이나 숫자만 와도 되나요? RFC 8259 기준으로는 됩니다. 예전 RFC 4627은 객체나 배열만 허용했기 때문에 오래된 파서는 거부할 수 있습니다.

날짜는 어떻게 넣나요? JSON에는 날짜 타입이 없어서 보통 "2026-10-16T09:00:00+09:00" 같은 ISO 8601 문자열로 넣습니다.

JSON과 YAML은 어떤 관계인가요? YAML 1.2는 JSON을 거의 그대로 포함하도록 설계되어, 대부분의 JSON 문서는 유효한 YAML이기도 합니다.