elastic/elasticsearch · error · XContentParseException

[{}] failed to parse object

Error message

[{}] failed to parse object

What it means

Thrown by ObjectParser.apply() when the underlying parse() method throws an IOException. The apply method is a convenience entry point that wraps checked IOException into an unchecked XContentParseException so callers do not need to handle IOException directly. The original IOException is attached as the cause.

Source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/ObjectParser.java:388

    private static void maybeMarkRequiredField(String currentFieldName, List<String[]> requiredFields) {
        Iterator<String[]> iter = requiredFields.iterator();
        while (iter.hasNext()) {
            String[] requiredFieldNames = iter.next();
            for (String field : requiredFieldNames) {
                if (field.equals(currentFieldName)) {
                    iter.remove();
                    break;
                }
            }
        }
    }

    @Override
    public Value apply(XContentParser parser, Context context) {
        try {
            return parse(parser, context);
        } catch (IOException e) {
            throw new XContentParseException(parser.getTokenLocation(), "[" + name + "] failed to parse object", e);
        }
    }

    public interface Parser<Value, Context> {
        void parse(XContentParser parser, Value value, Context context) throws IOException;
    }

    public void declareField(Parser<Value, Context> p, ParseField parseField, ValueType type) {
        if (parseField == null) {
            throw new IllegalArgumentException("[parseField] is required");
        }
        if (type == null) {
            throw new IllegalArgumentException("[type] is required");
        }
        FieldParser fieldParser = new FieldParser(p, type.supportedTokens(), parseField, type);
        for (String fieldValue : parseField.getAllNamesIncludedDeprecated()) {

            if (RestApiVersion.minimumSupported().matches(parseField.getForRestApiVersion())) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Inspect the cause (IOException) in the exception for the specific I/O failure type.
  2. Verify the request body is complete and not truncated by checking Content-Length matches actual body size.
  3. Ensure the input source (stream, bytes) is not consumed or closed before parsing.
  4. Check for encoding issues: valid UTF-8 for JSON, correct binary encoding for SMILE/CBOR.
Defensive patterns

Strategy: try-catch

Validate before calling

// Before parsing, verify the input is readable and non-empty
if (inputStream == null || (inputStream.available() == 0 && inputStream.markSupported())) {
    throw new IllegalArgumentException("Input stream is empty or null");
}

Try / catch

try {
    return objectParser.apply(parser, context);
} catch (XContentParseException e) {
    if (e.getCause() instanceof IOException ioEx) {
        logger.error("I/O failure during parsing: {}", ioEx.getMessage());
        return ResponseEntity.status(502).body("Upstream I/O error");
    }
    throw e;
}

Prevention

When it happens

Trigger: Any low-level I/O failure during XContent parsing: a closed or disconnected input stream, truncated bytes that cause the parser to hit EOF mid-token, encoding issues where the byte stream is not valid UTF-8 (for JSON), or SMILE/CBOR binary format corruption.

Common situations: Network connection dropping mid-request causing truncated body. Reverse proxy timeout cutting off the request body. Double-reading the input stream so it is exhausted before ObjectParser runs. Encoding mismatch (e.g., sending gzip-compressed bytes without declaring Content-Encoding).

Understand the failure class

Related errors


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