← 전체 글

JSON 데이터 뒤의 예상치 못한 비공백 문자: 수정 방법

이 오류는 완전한 JSON 값 뒤에 추가 내용이 있다는 뜻 —— 연결된 객체, 한 덩어리로 파싱된 NDJSON, 또는 끝의 쓰레기. 추가 데이터를 찾아 제거하는 법.

SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data 는 파서가 완전한 JSON 값 하나를 다 읽고서 —— 그 뒤에 공백이 아닌 내용을 발견했다는 뜻입니다. JSON은 최상위에서 값 정확히 하나만 허용하므로, 그 뒤에 따라오는 것은 모두 오류입니다. '추가 데이터'가 어떻게 생기고 어떻게 고치는지 정리합니다.

에러는 어떻게 보이나

// Firefox
SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data
  at line 1 column 18 of the JSON data

// V8 (Chrome / Node / Edge)
SyntaxError: Unexpected non-whitespace character after JSON at position 17
SyntaxError: Unexpected token { in JSON at position 17   // 예전 표현

// Python(유사)
json.decoder.JSONDecodeError: Extra data: line 1 column 18 (char 17)

위치는 유효한 값 다음 첫 문자를 가리킵니다 —— '추가'는 거기서 시작합니다.

왜 발생하는가

원인 1 —— 두 JSON 값을 이어 붙임

// ❌ 객체가 등 맞대고 —— 유효한 값, 그 뒤로 더
{"id":1}{"id":2}
//      ^ 위치 8: JSON 데이터 뒤의 비공백

// ✅ 배열로 감싸기
[{"id":1},{"id":2}]

원인 2 —— NDJSON / JSON Lines를 한 덩이로 파싱

로그 파일과 스트리밍 API는 자주 한 줄에 JSON 객체 하나(NDJSON)을 출력합니다. JSON.parse() 는 첫 줄의 값만 읽고, 다음 줄에서 걸립니다.

// ❌ 파일 전체에 JSON.parse
{"event":"login"}
{"event":"logout"}

// ✅ 줄 단위로 파싱
const rows = text
  .split('\n')
  .filter(Boolean)
  .map((line) => JSON.parse(line));

원인 3 —— 끝에 붙은 쓰레기나 중복된 응답

// ❌ 떠도는 텍스트, 중복된 payload, 또는 끝 세미콜론
{"ok":true};
{"ok":true}  // 프록시가 덧붙인 디버그 줄
extra

JSON-RPC와 프레이밍이 있는 다른 스트림

프로토콜을 소비 중이라면 —— stdio 위의 JSON-RPC, Language Server Protocol (LSP), Debug Adapter Protocol —— 여러 JSON 메시지가 설계상 같은 채널을 흐릅니다. 각 메시지에는 다음 메시지가 얼마나 긴지 알려주는 프레이밍 계층이 있어, 한 버퍼에서 두 값을 파싱하려 시도하지 않게 해 줍니다:

Content-Length: 87\r\n
\r\n
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}Content-Length: 42\r\n
\r\n
{"jsonrpc":"2.0","id":1,"result":{...}}

규칙: Content-Length 헤더를 읽고, 정확히 그만큼의 바이트를 읽고, 하나의 JSON 값을 파싱하고, 반복하라. 채널 전체를 들이마시고 한 번에 파싱하면 'unexpected non-whitespace character after JSON data' 에 부딪힙니다. 그 안에 값이 여러 개이기 때문입니다.

NDJSON의 대응 규칙은 '\n 으로 split 하고 각 줄을 파싱'. 공통점: JSON 메시지 스트림에는 항상 프레이밍 계층이 필요합니다 —— 그냥 이어 붙이는 것은 합법적 JSON이 아닙니다.

고치는 단계

  1. 보고된 위치로 가세요 —— 그 뒤의 모든 것이 '추가 데이터'. 첫 완전 값 바로 뒤에 무엇이 오는지 확인하세요.
  2. 여러 값? 리스트로 의도했다면 [ … ] 배열로 쉼표 구분해서 감싸세요.
  3. NDJSON / JSON Lines? 개행으로 split 하고 각 줄을 따로 파싱 —— 파일 전체를 한 번에 파싱하지 마세요.
  4. 끝에 쓰레기? 파싱 전에 잡문자(세미콜론, 중복된 payload, 디버그 출력)를 잘라 내세요.
  5. 스트리밍? 여러 응답을 하나의 버퍼로 합친 뒤 파싱하지 않는지 확인하세요.

자주 묻는 질문

'unexpected non-whitespace character after JSON data' 가 무슨 뜻?

파서가 유효한 JSON 값을 하나 읽고 그 뒤에서 더 많은 내용을 발견했다는 뜻입니다. JSON은 최상위 값을 단 하나만 허용하므로 뒤따르는 문자는 무효합니다.

여러 JSON 객체를 어떻게 파싱?

이어 붙어 있으면 배열로 감싸세요. 한 줄에 하나면(NDJSON / JSON Lines) 개행으로 split 하고 각 줄을 개별로 JSON.parse().

'Unexpected end of JSON input' 과 같은가?

반대입니다. 이 오류는 데이터가 너무 많다(완전한 값 뒤에 더); 'Unexpected end of JSON input' 은 데이터가 너무 적다(값이 잘림).

지금 고치기