SyntaxError: Unexpected token o in JSON at position 1 —— 그 소문자 o 는 [object Object] 의 두 번째 문자입니다. 이는 JSON 문자열이 아니라 JavaScript 객체를 직접 JSON.parse() 에 전달했다는 의미입니다. 이 글은 이 오류의 모든 변형과 각 경우를 1분 내에 수정하는 방법을 설명합니다.
오류 메시지에 "token o" 라고 나오는 이유
문자열이 아닌 값을 JSON.parse() 에 전달하면, JavaScript는 먼저 그것을 문자열로 강제 변환합니다. 일반 객체는 "[object Object]" 로 변환됩니다. 파서는 위치 0의 [ (유효 —— 배열의 시작)를 본 다음, 위치 1의 o (유효하지 않음 —— 유효한 배열 요소가 아님)를 만납니다. 그래서: Unexpected token o at position 1.
JSON.parse({})
// 동일: JSON.parse("[object Object]")
// SyntaxError: Unexpected token o in JSON at position 1가장 흔한 원인: response.json() 을 await 하지 않음
실제 코드베이스에서 이 오류의 1순위 원인입니다. fetch() 의 Response 객체는 문자열이 아니라 ReadableStream 래퍼입니다. 이것을 JSON.parse() 에 전달하면 "[object Response]" 로 강제 변환됩니다.
// ❌ 잘못 —— response 는 Response 객체이지 문자열이 아님
const response = await fetch('/api/user');
const data = JSON.parse(response);
// SyntaxError: Unexpected token o in JSON at position 1
// ✓ 올바름 —— 브라우저가 스트림을 JSON 으로 파싱하게 함
const data = await response.json();마찬가지로 response.text() 를 await 없이 호출하면 Promise 객체가 반환됩니다(이는 "[object Promise]" 로 강제 변환됨).
// ❌ await 누락 —— text 는 Promise 이지 문자열이 아님
const text = response.text();
const data = JSON.parse(text);
// SyntaxError: Unexpected token o in JSON at position 1
// ✓ 올바름
const text = await response.text();
const data = JSON.parse(text);이 오류를 유발하는 다른 객체들
| 전달한 것 | JS 가 강제 변환한 문자열 | 오류 토큰 |
|---|---|---|
{} 또는 모든 일반 객체 | "[object Object]" | 위치 1의 token o |
undefined | "undefined" | 위치 0의 token u |
true / false | "true" / "false" —— 사실 유효한 JSON! | 오류 없음 |
Response 객체 | "[object Response]" | 위치 1의 token o |
Promise | "[object Promise]" | 위치 1의 token o |
null | "null" —— 유효한 JSON | 오류 없음 (null 반환) |
원인: 직렬화하지 않고 객체를 전달
관련된 실수: 이미 메모리에 있는 JavaScript 객체를 "파싱"하려는 것. JSON.parse() 는 문자열 을 받습니다. 이미 객체를 갖고 있다면 파싱할 필요가 전혀 없습니다.
const config = { host: 'localhost', port: 3000 };
// ❌ 무의미 —— config 는 이미 객체임
const parsed = JSON.parse(config);
// ✓ 깊은 복사를 원하면 structuredClone 또는 stringify + parse
const clone = JSON.parse(JSON.stringify(config));
// ✓ 전송하려면 JSON.stringify
const body = JSON.stringify(config);원인: Python 등 백엔드가 잘못된 Content-Type 을 반환
때때로 서버는 "ok" 나 "not found" 같은 평문 에러 메시지를 200 상태로, 그리고 Content-Type 헤더 없이 반환합니다. 프런트엔드는 JSON 이라고 가정하고 response.json() 을 호출하면 본문이 유효한 JSON 이 아니어서 unexpected token 오류가 발생합니다.
// 서버가 리터럴 문자열을 보냄: ok
// 브라우저가 이를 JSON 으로 파싱 시도:
JSON.parse("ok")
// SyntaxError: Unexpected token o in JSON at position 0수정: response.json() 을 호출하기 전에 항상 response.ok 와 response.headers.get('Content-Type') 을 확인하세요:
const response = await fetch('/api/action');
if (!response.ok) {
const text = await response.text(); // 안전 —— JSON 이 아닐 수 있음
throw new Error(`HTTP ${response.status}: ${text}`);
}
const data = await response.json();덜 흔한 [object X] 변형
toString() 이 [object 로 시작하는 문자열을 반환하는 모든 값은 위치 1에서 같은 오류를 일으킵니다. [object Object] 외에 실제 코드에서 마주치는 것들:
[object Module]—— 동적 import 결과를 전달:const mod = await import('./data.json', { with: { type: 'json' } }). 원하는 것은mod.default이지mod가 아닙니다.[object AsyncFunction]—— 비동기 함수를 호출 하지 않고 참조를 전달한 경우:fn이 아니라fn()(프라미스의 해결값)을 문자열화하세요.[object HTMLDocument]——document를 실수로 전달(예: 오래된 디버거 스니펫에서).[object FormData]——fetch(url, { body: formData })는 괜찮지만,JSON.parse(formData)는 안 됩니다 —— 먼저Object.fromEntries(formData)로 변환하세요.
빠른 수정 체크리스트
- fetch + JSON.parse?
await response.json()로 교체하세요. - 중간에 await 가 빠졌는가? 파싱 전의 모든
async호출은 await 되어야 합니다. - 이미 객체를 가지고 있는가? 파싱할 필요 없습니다 —— 직접 사용하거나
structuredClone()으로 복제하세요. - 서버가 오류 시 JSON 이 아닌 응답을 반환하는가? 응답이 JSON 이 아닐 수 있을 때는
response.text()로 읽고,response.json()을 쓰지 마세요.
자주 묻는 질문
"Unexpected token o in JSON at position 1" 은 무슨 뜻인가요?
JavaScript 객체를 JSON.parse() 에 전달했다는 의미입니다. JavaScript는 객체를 "[object Object]" 라는 문자열로 강제 변환하고, 파서는 위치 0의 [ 는 수용하지만 위치 1의 o 는 거부합니다.
fetch 로는 어떻게 수정하나요?
JSON.parse(response) 를 호출하지 마세요. 대신 await response.json() 를 사용하면 응답 스트림을 읽고 자동으로 파싱해 줍니다. 체인의 각 단계가 await 되었는지 확인하세요.
이미 객체가 있는데 JSON.parse 가 필요한가요?
아니요. JSON.parse() 는 JSON 문자열 만 값으로 변환합니다. 이미 객체가 있다면 그대로 사용하거나, JSON.parse(JSON.stringify(obj)) 대신 structuredClone() 으로 깊은 복사를 하세요.
"Unexpected token o" 와 "[object Object] is not valid JSON" 은 같은 오류인가요?
근본 원인이 같습니다 —— 파싱 전에 객체가 문자열화된 것입니다. 최신 V8 빌드는 [object Object] is not valid JSON 표현을 출력하고, 이전 버전은 Unexpected token o 를 출력합니다. 전체 분석은 "[object Object] is not valid JSON" 수정하기 를 참고하세요.
원시 응답 확인하기
API 가 실제로 무엇을 반환하는지 모르겠다면, 원시 본문을 JSON Fix 에 붙여넣어 검증하세요. 유효한 JSON 이 아니면 검증기가 무엇이 잘못되었는지 정확히 알려줍니다.
- JSON Fix —— 브라우저에서 JSON 검증 및 복구
- "[object Object] is not valid JSON" 수정하기 —— JSON 구문 오류에 대한 완전한 가이드
- Unexpected end of JSON input —— 파서 가 구조가 완성되기 전에 데이터를 소진했을 때
- JavaScript 에서 손상된 JSON 처리하기 —— 안전 파싱 패턴과 오류 복구