elastic/elasticsearch · error · XContentEOFException
Unexpected end of file
Error message
Unexpected end of file
What it means
handleParserException maps Jackson's JsonEOFException to XContentEOFException with the message "Unexpected end of file". This fires when the parser hit physical end of input while still inside a value, object, or array - i.e. the document was truncated mid-stream.
Source
Thrown at libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java:76
JsonLocation loc = e.getLocation();
if (loc != null) {
return new XContentLocation(loc.getLineNr(), loc.getColumnNr(), loc.getByteOffset());
} else {
return null;
}
}
private static XContentParseException newXContentParseException(JsonProcessingException e) {
return new XContentParseException(getLocation(e), e.getMessage(), e);
}
/**
* Handle parser exception depending on type.
* This converts known exceptions to XContentParseException and rethrows them.
*/
static IOException handleParserException(IOException e) throws IOException {
switch (e) {
case JsonEOFException eof -> throw new XContentEOFException(getLocation(eof), "Unexpected end of file", e);
case JsonParseException pe -> throw newXContentParseException(pe);
case InputCoercionException ice -> throw newXContentParseException(ice);
case CharConversionException cce -> throw new XContentParseException(null, cce.getMessage(), cce);
case StreamConstraintsException sce -> throw newXContentParseException(sce);
default -> {
return e;
}
}
}
@Override
public Token nextToken() throws IOException {
try {
return convertToken(parser.nextToken());
} catch (IOException e) {
throw handleParserException(e);
}
}View on GitHub (pinned to db6a809a66)
Solutions
- Ensure the source stream delivers the complete document before parsing (read fully or check Content-Length)
- Add framing / length checks upstream of the parser
- Retry the read if the source is a flaky network stream
- Validate length before handing bytes to the parser
Example fix
// before: read may be partial
try (XContentParser p = XContentType.JSON.xContent().createParser(config, in)) {
p.nextToken();
}
// after: buffer fully first
byte[] bytes = in.readAllBytes();
try (XContentParser p = XContentType.JSON.xContent().createParser(config, new ByteArrayInputStream(bytes))) {
p.nextToken();
} Defensive patterns
Strategy: try-catch
Validate before calling
byte[] bytes = in.readAllBytes();
if (bytes.length == 0) throw new EOFException("empty input");
try (XContentParser p = XContentType.JSON.xContent().createParser(config, new ByteArrayInputStream(bytes))) {
p.nextToken();
} Type guard
static boolean isCompleteJson(byte[] b) {
try (var p = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, new ByteArrayInputStream(b))) {
while (p.nextToken() != null) {}
return true;
} catch (IOException e) { return false; }
} Try / catch
try { parser.nextToken(); }
catch (XContentEOFException e) { /* truncated upstream - refetch */ } Prevention
- Buffer the full body before parsing when possible
- Validate Content-Length against received bytes
- Retry truncated network reads once
When it happens
Trigger: Calling nextToken()/nextFieldName()/getText() etc. on a JsonXContentParser whose underlying stream ended before the JSON structure was complete.
Common situations: Truncated HTTP response body; network read cut short; a stream that was closed early; log/event payload missing the closing brace; chunked transfer that dropped the final chunk; feeding a parser from a byte array that was clipped.
Related errors
- Failed to parse content of branches.json
- Expected text at {} but found {}
- Failed to write keywords report
- expected data to start with an object
- repeated attribute key [{}]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/2f46aac298e423c7.
Report an issue: GitHub.