SonarSource/sonarqube · error · IllegalArgumentException
Cannot parse '%s' : %s
Error message
Cannot parse '%s' : %s
What it means
The SonarQube web API's filter/query parser (used by WS endpoints that accept criteria strings like 'languages = java') wraps any failure while parsing a single criterion into this IllegalArgumentException, preserving the raw criterion text and the underlying parse exception message. It is thrown from parseCriterion when none of the known criterion patterns (with or without an operator) match or an inner parser fails.
Source
Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/component/ws/FilterParser.java:68
public static List<Criterion> parse(String filter) {
return StreamSupport.stream(CRITERIA_SPLITTER.split(filter).spliterator(), false)
.map(FilterParser::parseCriterion)
.toList();
}
private static Criterion parseCriterion(String rawCriterion) {
try {
return Stream.of(
tryParsingCriterionWithoutOperator(rawCriterion),
tryParsingCriterionWithInOperator(rawCriterion),
tryParsingCriterionWithComparisonOperator(rawCriterion)
)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("Criterion is invalid"));
} catch (Exception e) {
throw new IllegalArgumentException(String.format("Cannot parse '%s' : %s", rawCriterion, e.getMessage()), e);
}
}
private static Optional<Criterion> tryParsingCriterionWithoutOperator(String criterion) {
Matcher matcher = PATTERN_WITHOUT_OPERATOR.matcher(criterion);
if (!matcher.matches()) {
return Optional.empty();
}
Criterion.Builder builder = new Criterion.Builder();
builder.setKey(matcher.group(1));
return Optional.of(builder.build());
}
private static Optional<Criterion> tryParsingCriterionWithComparisonOperator(String criterion) {
Matcher matcher = PATTERN_WITH_COMPARISON_OPERATOR.matcher(criterion);
if (!matcher.matches()) {
return Optional.empty();
}View on GitHub (pinned to 184c821202)
Solutions
- Inspect the raw criterion echoed in the message and fix it to match '<key> <operator> <value>' (e.g. 'languages = java', 'rating > 3').
- Check for whitespace/encoding problems (trailing spaces, URL-encoding, quotes) in the criterion string.
- Validate each criterion against the documented operator set for the endpoint before sending.
- Upgrade/align client code with the SonarQube version's FilterParser grammar if syntax changed between versions.
Example fix
// before String criteria = "languages: java"; // invalid separator // after String criteria = "languages = java"; // '<key> <operator> <value>'
Defensive patterns
Strategy: validation
Validate before calling
String VALID = "^(?<key>[a-zA-Z_]+)\\s*(?<op>=|!=|<=|>=|<|>|IN)\\s*(?<value>.+)$";
if (!rawCriterion.matches(VALID)) {
throw new IllegalArgumentException("Invalid criterion (expected '<key> <operator> <value>'): " + rawCriterion);
} Try / catch
try {
ws.search(criteria);
} catch (SonarError e) {
if (e.getMessage().startsWith("Cannot parse '")) {
log.warn("Bad criterion '{}': fix syntax", criteria);
} else throw e;
} Prevention
- Build criteria programmatically from typed key/operator/value triples instead of raw strings.
- URL-encode criteria properly when sending over HTTP.
- Test filter strings against the target SonarQube version's grammar.
When it happens
Trigger: Passing a malformed criterion string to a Web API that accepts filter criteria (e.g. api/projects/search with a 'criteria'-style parameter); the criterion string does not match the expected '<key> <operator> <value>' grammar (typo, missing operator, unquoted spaces, invalid operator).
Common situations: Copy-pasted filter strings with extra whitespace or smart quotes; custom dashboards or scripts building criteria by string concatenation; API version changes that added/renamed operators leaving old clients sending unsupported syntax.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Message '%s' cannot be dismissed.
- ${e.getMessage()}
- Languages should be set either by using 'languages = java' o
- Tags should be set either by using 'tags = java' or 'tags IN
- Value '%s' is not a number
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/40ee988bcfb3bba3.
Report an issue: GitHub.