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

  1. Ensure the source stream delivers the complete document before parsing (read fully or check Content-Length)
  2. Add framing / length checks upstream of the parser
  3. Retry the read if the source is a flaky network stream
  4. 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

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


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/2f46aac298e423c7. Report an issue: GitHub.