C# 보고된 사례에서 메시지 문구를 옮긴 것이며, 여기서 실행하지는 않았습니다.
Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
JsonConvert.DeserializeObject에 JSON 값으로 시작하지 않는 무언가가 넘어갔습니다. line 0 position 0은 맨 첫 글자에서 실패했다는 뜻입니다. 메시지에 나온 문자가 실제로 무엇을 들고 있는지 알려 줍니다.
JSON을 붙여넣고 어디서 깨지는지 정확히 확인하기
입력
붙여 넣은 것은 여러분의 브라우저를 떠나지 않습니다. connect-src 허용 목록 덕분에 이는 약속이 아니라 브라우저가 강제하는 보장입니다. 직접 확인하기
실제 원인
어느 쪽이 답인 경우가 많은지, 그 순서대로 정리했습니다.
-
01 파일 내용 대신 파일 경로를 넘김
DeserializeObject가 받는 건 JSON 문자열이지 파일 이름이 아닙니다. 경로를 넘기면 파서가 C:\...를 문서로 읽고 문자 C나 슬래시에서 실패합니다. 아주 흔한 실수인데 메시지는 그 점을 전혀 암시하지 않습니다.
깨지는 예
var data = JsonConvert.DeserializeObject<Model>(@"C:\data\input.json");되는 예
var json = File.ReadAllText(@"C:\data\input.json"); var data = JsonConvert.DeserializeObject<Model>(json); -
02 응답이 HTML
오류 페이지, 로그인 리다이렉트, 또는 IIS 오류입니다. 메시지의 문자는 < 가 됩니다. 역직렬화 전에 본문을 문자열로 읽어 확인하세요.
깨지는 예
var data = JsonConvert.DeserializeObject<Model>(await res.Content.ReadAsStringAsync());되는 예
var body = await res.Content.ReadAsStringAsync(); if (!res.IsSuccessStatusCode || !body.TrimStart().StartsWith("{")) throw new InvalidOperationException($"{(int)res.StatusCode}: {body[..Math.Min(300, body.Length)]}"); var data = JsonConvert.DeserializeObject<Model>(body); -
03 문자열 앞의 바이트 순서 표식
인코딩 감지기가 BOM을 떼어 내게 하지 않은 채 파일을 읽으면 JSON 앞에 U+FEFF가 남습니다.
다른 런타임에서의 같은 실수
밑바탕의 문제는 똑같고, 다른 건 문구뿐입니다. 동료가 이 중 하나를 들고 왔다면, 그 사람이 보고 있는 건 여러분이 보는 것과 같습니다.
| C# (System.Text.Json) | '<' is an invalid start of a value. Path: $ | LineNumber: 0 | BytePositionInLine: 0. |
|---|---|
| JavaScript (V8) | Unexpected token '<', "<!DOCTYPE "... is not valid JSON |
자주 묻는 질문
- System.Text.Json으로 옮겨야 하나요?
- .NET Core 3.0부터의 기본 선택지이고 더 빠릅니다. 다만 더 엄격하기도 합니다. 작은따옴표 문자열도, 끝쉼표도, 명시적으로 켜지 않는 한 주석도 받지 않습니다. Newtonsoft의 너그러움에 기대던 코드는 만들어 내는 쪽을 고쳐야 합니다.