elastic/elasticsearch · error · IllegalArgumentException
Unmatched quote
Error message
Unmatched quote
What it means
Thrown by CsvParser when the input line ends while the state machine is still inside QUOTED state, meaning an opening quote was never matched by a closing quote. The parser reaches end-of-string having never transitioned out of QUOTED, which it treats as malformed CSV. This is a hard parse error from the CsvProcessor's line parser.
Source
Thrown at modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/CsvParser.java:81
return;
}
break;
case QUOTED:
processQuoted();
break;
case QUOTED_END:
if (processQuotedEnd()) {
return;
}
break;
}
}
// we've reached end of string, we need to handle last field
switch (state) {
case UNQUOTED -> setField(length);
case QUOTED_END -> setField(length - 1);
case QUOTED -> throw new IllegalArgumentException("Unmatched quote");
}
}
private boolean processStart() {
for (; currentIndex < length; currentIndex++) {
char c = currentChar();
if (c == quote) {
state = State.QUOTED;
builder.setLength(0);
startIndex = currentIndex + 1;
return false;
} else if (c == separator) {
startIndex++;
builder.setLength(0);
if (setField(startIndex)) {
return true;
}
} else if (isWhitespace(c)) {View on GitHub (pinned to db6a809a66)
Solutions
- Verify the configured 'quote' character on the csv processor matches the producer's quoting.
- Ensure multi-line quoted records are joined into a single string field before the csv processor runs (use a multiline codec upstream).
- Inspect the raw input line for the unclosed quote and fix the producer.
- Add an 'on_failure' handler to quarantine malformed records.
Example fix
// before - field delivered line-by-line, quoted field spans lines
{"csv": {"field": "message", "target_fields": ["a","b"]}}
// after - join multiline records first, then parse
{"multiline": {...}},
{"csv": {"field": "message", "target_fields": ["a","b"], "quote": "\""}} Defensive patterns
Strategy: validation
Validate before calling
// Ensure the source field is a single complete line before the csv processor by joining multiline records upstream (filebeat multiline codec).
// In a script processor, you can also pre-check for balanced quotes:
{"script": {"source": "long q = ctx.message.chars().filter(c -> c == '\"').count(); if (q % 2 != 0) { throw new Exception('unbalanced quotes'); }"}} Try / catch
{"on_failure": [{"set": {"field": "failure", "value": "csv-unmatched-quote"}}, {"index": {"index": "csv-dlq"}}]} Prevention
- Use a multiline codec on the shipper so quoted fields spanning newlines are reassembled.
- Confirm the configured quote character matches the producer.
- Quarantine malformed records rather than dropping them.
When it happens
Trigger: A csv processor parses a line where a quoted field opens with the configured quote char but the line is truncated before the closing quote, e.g. value="abc with no terminator, or an embedded quote that was not properly escaped/doubled.
Common situations: Log shippers splitting multi-line CSV records across lines (CSV fields legitimately contain newlines within quotes); misconfigured quote characters; truncated UDP/syslog payloads; copy-paste artifacts that lost a quote.
Related errors
- Illegal character inside unquoted field at {}
- character '{}' after quoted field at {}
- unable to convert [{}] to float
- field [{}] is null, cannot process it.
- cannot expand [{}], because [{}] is not an object field, but
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/6ca31dcef5a50ed8.
Report an issue: GitHub.