quarkusio/quarkus · error · IllegalArgumentException
Only Latin characters are supported:
Error message
Only Latin characters are supported:
What it means
HtmlEscaper's replacement table maps byte values 0-255 to escape-replacement ids. setLatinReplacementId() throws IllegalArgumentException when asked to register a character code greater than 255, because the table only covers Latin-1 characters. This guards the static table-building code from non-Latin characters.
Source
Thrown at independent-projects/qute/core/src/main/java/io/quarkus/qute/HtmlEscaper.java:37
private static byte[] createLatinReplacementData() {
byte[] data = new byte[256];
// by default we don't escape anything i.e. the escaped index is 0!
setLatinReplacementId(data, '"', 1);
setLatinReplacementId(data, '\'', 2);
setLatinReplacementId(data, '&', 3);
setLatinReplacementId(data, '<', 4);
setLatinReplacementId(data, '>', 5);
assert getLatinReplacementId(data, '"') == 1;
assert getLatinReplacementId(data, '\'') == 2;
assert getLatinReplacementId(data, '&') == 3;
assert getLatinReplacementId(data, '<') == 4;
assert getLatinReplacementId(data, '>') == 5;
return data;
}
private static void setLatinReplacementId(byte[] data, int c, int id) {
if (c > 255) {
throw new IllegalArgumentException("Only Latin characters are supported: " + c);
}
if (id < 0 || id > 15) {
throw new IllegalArgumentException("Replacement ID must be in range [0, 15] but was: " + id);
}
data[c] = (byte) id;
}
private static int getLatinReplacementId(byte[] data, int c) {
return data[c] & REPLACEMENT_ID_MASK;
}
private static String replacementOf(char c) {
if (c > 255) {
return null;
}
int replacementId = getLatinReplacementId(LATIN_REPLACEMENT_ID_TABLE, c & 0xFF);
// in the super class we still have to perform a null check vs String, which means
// we can have a branch misprediction there.View on GitHub (pinned to e1c734241f)
Solutions
- Only register escape replacements for characters with code point <= 255 in the table.
- Handle non-Latin characters with a separate escaping mechanism (e.g. a map checked before the byte table).
- If this fires unexpectedly, audit any local modifications to createLatinReplacementData for bad character constants.
Example fix
// before
setLatinReplacementId(data, '\u2014', 12); // em dash > 255 -> throws
// after
if ('\u2014' <= 255) {
setLatinReplacementId(data, '\u2014', 12);
} // handle em dash elsewhere, e.g. in a separate unicode escape map Defensive patterns
Strategy: validation
Validate before calling
if (codePoint > 255) {
// route to a separate unicode escaping path, not the Latin-1 byte table
} Type guard
boolean isLatin1(int c) { return c >= 0 && c <= 255; } Try / catch
try {
setLatinReplacementId(data, c, id);
} catch (IllegalArgumentException ex) {
LOGGER.error("non-Latin escape char in table: {}", ex.getMessage());
throw ex;
} Prevention
- Only register characters with code point <= 255 in HtmlEscaper's table
- Escape non-Latin characters via a separate mechanism
- Add an assertion/test iterating table entries for code point bounds
When it happens
Trigger: Internal configuration/build of the escape table with a character code > 255 — practically only reachable if createLatinReplacementData is modified or a caller registers a non-Latin (e.g. Unicode) character as a replacement target.
Common situations: Contributing a patch or customizing HtmlEscaper to add extra escape characters and using a code point beyond 255 (e.g. typographic quotes, em dash).
Related errors
- Replacement ID must be in range [0, 15] but was:
- Invalid identifier found: [id]
- Literal must not be null
- Unexpected tag: " + tag
- Expresion command must be an ASCII char: " + command
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/92343406510c53a5.
Report an issue: GitHub.