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

  1. Inspect the raw criterion echoed in the message and fix it to match '<key> <operator> <value>' (e.g. 'languages = java', 'rating > 3').
  2. Check for whitespace/encoding problems (trailing spaces, URL-encoding, quotes) in the criterion string.
  3. Validate each criterion against the documented operator set for the endpoint before sending.
  4. 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

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


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/40ee988bcfb3bba3. Report an issue: GitHub.