SonarSource/sonarqube · error · IllegalArgumentException
Can't URI decode
Error message
Can't URI decode: ${param} What it means
parseComplianceStandardsFilter URL-decodes its input with URLDecoder.decode before parsing key/value pairs. If the raw parameter contains malformed percent-encoding (e.g. a trailing '%' or invalid hex sequence), URLDecoder throws IllegalArgumentException, which is rethrown as 'Can't URI decode: <param>'.
Solutions
- Percent-encode the filter value properly (encodeURIComponent / URLEncoder.encode) before sending
- Check the value has no bare '%' characters; every '%' must be followed by two hex digits
- Decode on the client side only once — avoid double-encoding
- Sanitize or strip characters that are not valid in the filter before calling the API
Example fix
// before
GET /api/...?filter=standard%zz=SECURITY
// after
const param = encodeURIComponent('standard=SECURITY'); // standard%3DSECURITY Defensive patterns
Strategy: validation
Validate before calling
function isUriDecodable(s) {
try { decodeURIComponent(s); return true; } catch { return false; }
}
// check every '%' is followed by two hex digits before calling the API Try / catch
try {
await api.searchIssues({ complianceStandards: rawFilter });
} catch (e) {
if (e.status === 400 && /Can't URI decode/.test(e.message)) {
throw new Error(`Malformed percent-encoding in filter '${rawFilter}'`);
}
throw e;
} Prevention
- Always percent-encode filter parameters with encodeURIComponent/URLEncoder.encode
- Never manually splice already-encoded values (avoid double encoding)
- Round-trip test decode(encode(x)) === x in tests
- Strip stray '%' characters from user input
When it happens
Trigger: Passing a complianceStandards filter containing an invalid percent-escape such as '%zz', a lone '%', or a truncated escape like 'M2'.
Common situations: Double- or under-encoding query parameters when building requests by hand; copying values out of logs where '+' and '%' were mangled; a proxy stripping part of the encoded value.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- Invalid format:
- Invalid impact format
- a JVM option can't be empty and must start with '-'. The…
- a JVM option can't overwrite mandatory JVM options. The…
- a JVM option can't overwrite mandatory JVM options.
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/62fe3c4c7c1299b9.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/common/ParamParsingUtils.java:58
public static Pair<SoftwareQuality, Severity> parseImpact(String impact) {
String[] parts = impact.split("=");
if (parts.length != 2) {
throw new IllegalArgumentException("Invalid impact format: " + impact);
}
return Pair.of(SoftwareQuality.valueOf(parts[0]),
Severity.valueOf(parts[1]));
}
public static Map<ReportKey, Set<String>> parseComplianceStandardsFilter(@Nullable String param) {
if (param == null) {
return Map.of();
}
String decodedParam;
try {
decodedParam = URLDecoder.decode(param, StandardCharsets.UTF_8);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Can't URI decode: " + param, e);
}
Map<ReportKey, Set<String>> categoriesByStandard = new HashMap<>();
String[] parts = decodedParam.split("&");
for (String part : parts) {
String[] keyValue = part.split("=");
if (keyValue.length != 2) {
throw new IllegalArgumentException("Invalid format: " + decodedParam);
}
Set<String> values = Arrays.stream(keyValue[1].split(",")).filter(s -> !s.isBlank()).collect(Collectors.toSet());
categoriesByStandard.put(ReportKey.parse(keyValue[0]), values);
}
return categoriesByStandard;
}
}
View on GitHub (pinned to 184c821202)