quarkusio/quarkus · error · IllegalArgumentException

String not closed

Error message

String not closed

What it means

readString() consumes characters until a closing '"'. If the end of input is reached while still inside a string literal, the string was never closed and the reader throws IllegalArgumentException. This catches unterminated string values in malformed JSON.

Source

Thrown at independent-projects/bootstrap/json/src/main/java/io/quarkus/bootstrap/json/JsonReader.java:224

                return new JsonString(value);
            }

            if ('\\' == ch) {
                if (unescapedValue == null) {
                    unescapedValue = new StringBuilder().append(text, start, position - 1);
                }
                final int escaped = nextChar();
                if (escaped == 'u') {
                    unescapedValue.append(readUnicode());
                } else {
                    unescapedValue.appendCodePoint(unescape(escaped));
                }
            } else if (unescapedValue != null) {
                unescapedValue.appendCodePoint(ch);
            }
        }

        throw new IllegalArgumentException("String not closed");
    }

    private static int unescape(int ch) {
        return switch (ch) {
            case 'b' -> '\b';
            case 'n' -> '\n';
            case 't' -> '\t';
            case 'f' -> '\f';
            case 'r' -> '\r';
            default -> ch;
        };
    }

    private char readUnicode() {
        final int digit1 = Character.digit(nextChar(), 16);
        final int digit2 = Character.digit(nextChar(), 16);
        final int digit3 = Character.digit(nextChar(), 16);
        final int digit4 = Character.digit(nextChar(), 16);

View on GitHub (pinned to e1c734241f)

Solutions

  1. Add the missing closing double quote to the string value
  2. Escape any inner double quotes as \" so the string terminates where intended
  3. Validate the JSON and inspect the tail of the input to see where the string is left open

Example fix

// before
{"quote":"He said "hi""}
// after
{"quote":"He said \"hi\""}
Defensive patterns

Strategy: try-catch

Validate before calling

// Quick sanity check: an even number of unescaped double quotes
int count = 0;
for (int i = 0; i < jsonText.length(); i++) {
    if (jsonText.charAt(i) == '"' && (i == 0 || jsonText.charAt(i - 1) != '\\')) count++;
}
if (count % 2 != 0) {
    throw new IllegalArgumentException("Odd number of unescaped quotes — unterminated string");
}

Try / catch

try {
    JsonValue v = new JsonReader(text).read();
} catch (IllegalArgumentException e) {
    if (e.getMessage().equals("String not closed")) {
        // inspect the tail of the input for a missing quote or unescaped inner quote
    }
}

Prevention

When it happens

Trigger: A string value missing its final quote, e.g. '{"name": "abc' — the parser consumes to EOF and throws. Also caused by an unescaped '"' earlier in the string swallowing the intended closing quote.

Common situations: Hand-editing JSON and deleting a quote; unescaped inner quotes like "He said "hi"" leaving the string unterminated; truncated payloads ending mid-string.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/4f3a9b8047cb6b2d. Report an issue: GitHub.