← Debugging Guides

阅读中文版本

Rust serde_json: EOF while parsing a value

Fix serde_json "EOF while parsing" errors caused by empty bodies, truncated responses, or deserializing into the wrong shape.

intermediatedebuggingrustjsonserde

Symptoms

  • Error("EOF while parsing a value", line: 1, column: 0)
  • Deserialization fails only when the HTTP body is empty
  • The error reports a nonzero column implying truncation

Possible causes

  • An HTTP body is empty (204 or a failed request) but parsed as JSON
  • The response was truncated mid-transfer
  • Deserializing a stream with from_reader after the reader was consumed
  • The content is not JSON at all (HTML error page)

Diagnosis steps

Log the raw body before deserializing

let body = resp.text().await?; println!("{body}");

Interpretation

An empty string or HTML explains column 0 or a mid-value EOF.

Check the HTTP status before parsing

Interpretation

A 204 or 500 body should be handled as an error, not fed to the JSON parser.

Match the deserialization target to the payload shape

Interpretation

A type mismatch elsewhere in the value can also surface as an EOF at the last field.

Root cause

serde_json streams tokens and expects a complete JSON value. An empty or truncated body makes the parser hit end-of-input before finishing a value, producing "EOF while parsing". The exact column distinguishes an empty body (column 0) from truncation deeper in the document.

Fix

Check status and emptiness before parsing: read the body into a String, verify it is non-empty, and only then call serde_json::from_str. For optional bodies use an enum or Option. When truncation is possible, validate Content-Length and retry, and never assume a 200 always carries a parseable JSON body.

Verify the fix

Re-run against the endpoint that returned empty; the code now handles the empty case without a parse error, and a test feeding an empty string asserts a clear application error instead of an EOF panic.

Symptoms

Deserialization fails with EOF while parsing a value at line 1 column 0 or a nonzero column deeper in the stream. It correlates strongly with empty bodies or truncated responses rather than with valid JSON.

Diagnosis

Inspect the raw body and status before parsing:

let status = resp.status();
let body = resp.text().await?;
eprintln!("status={status} body={body:?}");
let value: Value = serde_json::from_str(&body)?;

Column 0 means an empty input; a later column means truncation or a handoff bug.

Fix

Guard empty and non-JSON bodies:

if !status.is_success() {
    return Err(format!("http {status}").into());
}
if body.trim().is_empty() {
    return Ok(None); // or a defined default
}
let value = serde_json::from_str(&body)?;

Verification

Call the endpoint that used to return an empty body; no EOF error occurs, and a test deserializing “” returns a clear message rather than a serde EOF.

Additional Notes

An end-of-input error during parsing almost always means the bytes are not what the parser expected: empty because a request failed, truncated because a transfer ended early, or not json at all because an error page arrived instead. Checking the status code and trimming the body before parsing converts a confusing parse error into a clear contract violation. Comparing the declared content length to the received size detects truncation, and treating an empty body as a defined case rather than valid json stops the parser from becoming the place where unrelated failures surface.