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

  1. Verify the configured 'quote' character on the csv processor matches the producer's quoting.
  2. Ensure multi-line quoted records are joined into a single string field before the csv processor runs (use a multiline codec upstream).
  3. Inspect the raw input line for the unclosed quote and fix the producer.
  4. 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

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


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