elastic/elasticsearch · error · XContentParseException

Failed to derive xcontent

Error message

Failed to derive xcontent

What it means

Thrown by the deprecated XContentFactory.xContent(CharSequence) when xContentType(content) returns null, meaning the character sequence does not match the signature of any known XContent format (JSON, YAML, SMILE, CBOR). The method guesses format from leading bytes/characters and fails if no format matches.

Source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/XContentFactory.java:181

            if (Character.isWhitespace(c) == false) {
                break;
            }
        }
        return null;
    }

    /**
     * Guesses the content (type) based on the provided char sequence and returns the corresponding {@link XContent}
     *
     * @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
     * The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
     * This method is deprecated to prevent usages of it from spreading further without specific reasons.
     */
    @Deprecated
    public static XContent xContent(CharSequence content) {
        XContentType type = xContentType(content);
        if (type == null) {
            throw new XContentParseException("Failed to derive xcontent");
        }
        return xContent(type);
    }

    /**
     * Guesses the content type based on the provided bytes and returns the corresponding {@link XContent}
     *
     * @deprecated the content type should not be guessed except for few cases where we effectively don't know the content type.
     * The REST layer should move to reading the Content-Type header instead. There are other places where auto-detection may be needed.
     * This method is deprecated to prevent usages of it from spreading further without specific reasons.
     */
    @Deprecated
    public static XContent xContent(byte[] data) {
        return xContent(data, 0, data.length);
    }

    /**
     * Guesses the content type based on the provided bytes and returns the corresponding {@link XContent}

View on GitHub (pinned to db6a809a66)

Solutions

  1. Specify the content type explicitly instead of relying on auto-detection (pass XContentType to the parser).
  2. Ensure the CharSequence is non-empty and starts with a valid format indicator (e.g., '{' or '[' for JSON).
  3. If the content is binary (SMILE/CBOR), use the byte[] overload, not CharSequence.
  4. Migrate away from the deprecated xContent(CharSequence) method; read Content-Type from the request header.

Example fix

// before — deprecated auto-detection
XContent x = XContentFactory.xContent(charSequence);

// after — explicit type from header
XContentType type = XContentType.fromMediaType(contentTypeHeader);
XContent x = XContentFactory.xContent(type);
Defensive patterns

Strategy: validation

Validate before calling

// Before calling xContent(CharSequence), verify content is non-empty and detectable
public static XContentType detectOrThrow(CharSequence content) {
    if (content == null || content.length() == 0 || content.toString().isBlank()) {
        throw new IllegalArgumentException("Content is empty, cannot detect type");
    }
    XContentType type = XContentFactory.xContentType(content);
    if (type == null) {
        throw new IllegalArgumentException("Content does not match JSON, YAML, SMILE, or CBOR");
    }
    return type;
}

Try / catch

try {
    XContent x = XContentFactory.xContent(content);
} catch (XContentParseException e) {
    if ("Failed to derive xcontent".equals(e.getMessage())) {
        // Fallback: ask caller for explicit content type
        throw new IllegalStateException("Cannot detect content type; specify XContentType explicitly", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing an empty string, a string with only whitespace, a string whose first non-whitespace character does not match any known format's magic bytes/leading character, or a string containing non-UTF-8 binary data (e.g., SMILE bytes passed as a CharSequence).

Common situations: Auto-detection on empty or whitespace-only bodies. Passing binary SMILE/CBOR content as a string (corrupting it). Receiving garbled input from a malfunctioning upstream service. Using the deprecated xContent(CharSequence) API instead of specifying the content type explicitly.

Related errors


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