C# 報告された事例からメッセージ文を書き写したもので、ここでは実行していません。
Unexpected character encountered while parsing value: <. Path '', line 0, position 0.
JsonConvert.DeserializeObjectに、JSONの値で始まっていないものが渡されました。line 0 position 0 は、最初の1文字で失敗したという意味です。メッセージに出ている文字が、実際に手元にあるものを教えてくれます。
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の寛容さに頼っていたコードは、生成する側を直す必要があります。