quarkusio/quarkus · error · IllegalArgumentException
Unexpected character '${str.charAt(pos)}' at position ${pos}
Error message
Unexpected character '${str.charAt(pos)}' at position ${pos}: ${str} What it means
peekToken() throws this IllegalArgumentException when it encounters a character that cannot begin or continue a valid token in a Java type signature at the given position. It is the sibling of the 'Unexpected end of input' error and includes the offending character, its position, and the full string to make the malformed input easy to locate.
Source
Thrown at core/deployment/src/main/java/io/quarkus/deployment/types/TypeParser.java:221
// token is a keyword or fully qualified name
int begin = pos;
while (pos < str.length() && Character.isJavaIdentifierStart(str.charAt(pos))) {
do {
pos++;
} while (pos < str.length() && Character.isJavaIdentifierPart(str.charAt(pos)));
if (pos < str.length() && str.charAt(pos) == '.') {
pos++;
} else {
return str.substring(begin, pos);
}
}
if (pos == str.length()) {
throw new IllegalArgumentException("Unexpected end of input: " + str);
}
throw new IllegalArgumentException("Unexpected character '" + str.charAt(pos) + "' at position " + pos + ": " + str);
}
private String nextToken() {
String result = peekToken();
pos += result.length();
return result;
}
private boolean isSpecial(char c) {
return c == ',' || c == '?' || c == '<' || c == '>' || c == '[' || c == ']';
}
}
View on GitHub (pinned to e1c734241f)
Solutions
- Read the position reported in the message and inspect that character in the string
- Remove or replace the illegal character; use fully qualified binary names for reference types
- Do not pass JVM descriptor syntax ('Ljava/lang/String;') where a source-like name ('java.lang.String') is expected
- Pre-validate the signature with a regex/checksum or unit test before parsing
Example fix
// before
new TypeParser("Ljava/util/List;").parse(); // Unexpected character ';' at position 14
// after
new TypeParser("java.util.List").parse(); Defensive patterns
Strategy: validation
Validate before calling
boolean isSourceStyleTypeName(String s) {
return s != null && s.matches("[\\w.$]+(<[\\s\\S]+>)?(\\[\\])*");
} Type guard
// convert JVM descriptor form to source-style before parsing
String normalizeToSourceName(String s) {
if (s != null && s.startsWith("L") && s.endsWith(";")) {
return s.substring(1, s.length() - 1).replace('/', '.');
}
return s;
} Try / catch
try {
new TypeParser(sig).parse();
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Unexpected character")) {
int pos = Integer.parseInt(e.getMessage().replaceFirst(".*position (\\d+):.*", "$1"));
throw new IllegalArgumentException("Illegal char at index " + pos + " in " + sig, e);
}
throw e;
} Prevention
- Use source-style names (java.lang.String), not descriptors (Ljava/lang/String;)
- Strip whitespace and control characters before parsing
- Copy type names from canonical sources (class.getName()), not from bytecode dumps
- Sanitize user-supplied type strings with a strict regex
When it happens
Trigger: Parsing strings containing characters outside the token alphabet — e.g. 'java.util.List<String>' (unqualified generic name with a bare 'S' is fine, but 'java.util.List@' or 'com.Foo;extra' contain characters the lexer does not accept), stray semicolons, commas in wrong places, or ASCII artifacts from copy/paste.
Common situations: Users pasting descriptor-style or internal names (e.g. 'Ljava/util/List;' with semicolons) into APIs that expect source-style names; typos in configured class names; strings containing whitespace or control characters not handled by the tokenizer.
Related errors
- Unexpected end of input: ${str}
- unbalanced quotes in
- invalid config ${comment}
- Could not parse HTML entity &${abbrev}; in ${text}
- Unable to parse: ${javadocPath}
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/96e5c71b0fb8b686.
Report an issue: GitHub.