elastic/elasticsearch · error · IllegalArgumentException
Expected text at {} but found {}
Error message
Expected text at {} but found {} What it means
throwOnNoText is called when the caller asked for text (e.g. text(), optimizedText(), or charBuffer()) but the current token is not a value token that carries text - for example the parser is positioned on START_OBJECT, START_ARRAY, FIELD_NAME, or END_*. The exception names the token location and the offending currentToken().
Source
Thrown at libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentParser.java:165
public XContentString optimizedText() throws IOException {
if (currentToken().isValue() == false) {
throwOnNoText();
}
var parser = this.parser;
if (parser instanceof FilteringParserDelegate delegate) {
parser = delegate.delegate();
}
if (parser instanceof OptimizedTextCapable optimizedTextCapableParser) {
var bytesRef = optimizedTextCapableParser.getValueAsText();
if (bytesRef != null) {
return bytesRef;
}
}
return new Text(text());
}
private void throwOnNoText() {
throw new IllegalArgumentException("Expected text at " + getTokenLocation() + " but found " + currentToken());
}
@Override
public CharBuffer charBuffer() throws IOException {
try {
return CharBuffer.wrap(parser.getTextCharacters(), parser.getTextOffset(), parser.getTextLength());
} catch (IOException e) {
throw handleParserException(e);
}
}
@Override
public Object objectText() throws IOException {
JsonToken currentToken = parser.getCurrentToken();
if (currentToken == JsonToken.VALUE_STRING) {
return text();
} else if (currentToken == JsonToken.VALUE_NUMBER_INT || currentToken == JsonToken.VALUE_NUMBER_FLOAT) {
return parser.getNumberValue();View on GitHub (pinned to db6a809a66)
Solutions
- Always advance the parser to a value token (via nextToken()) before calling text()
- Switch on currentToken() and only call text() for VALUE_* tokens
- Use nextFieldName()/nextString() helpers that handle positioning for you
Example fix
// before parser.nextToken(); // lands on FIELD_NAME "name" String v = parser.text(); // throws - FIELD_NAME is not a value // after parser.nextToken(); // FIELD_NAME "name" parser.nextToken(); // VALUE_STRING String v = parser.text();
Defensive patterns
Strategy: type-guard
Validate before calling
XContentParser.Token t = parser.currentToken();
if (t == null || !t.isValue()) {
throw new IllegalStateException("expected value token, got " + t);
}
String v = parser.text(); Type guard
static boolean isValueToken(XContentParser.Token t) {
return t != null && t.isValue();
} Try / catch
try { parser.text(); }
catch (IllegalArgumentException e) { /* advance token first */ } Prevention
- Always advance to a value token before text() Switch on currentToken() and only read text for VALUE_* Use nextFieldName/nextString helpers for common patterns
When it happens
Trigger: Calling a text-expecting method on JsonXContentParser when currentToken() is not a scalar value token (VALUE_STRING, VALUE_NUMBER, VALUE_TRUE, etc.). The optimized-text path also falls back to text() and calls throwOnNoText if the value-as-text lookup returns null.
Common situations: Forgetting to call nextToken() before reading text; reading text() at FIELD_NAME position expecting the field's value; consuming a token type the caller did not check; an off-by-one in a manual token loop.
Related errors
- Can't write raw bytes whose xcontent-type can't be guessed
- Unexpected end of file
- Failed to parse content of branches.json
- 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/5b4e8378580d3f2e.
Report an issue: GitHub.