SonarSource/sonarqube · error · IllegalArgumentException
Locale cannot be parsed as a BCP47 language tag
Error message
Locale cannot be parsed as a BCP47 language tag
What it means
IndexAction (api/system/index) validates the mandatory locale parameter by parsing it as a BCP47 language tag: Locale.forLanguageTag plus getISO3Language must resolve to a known ISO3 language. If the tag is empty after parsing or unknown (MissingResourceException), IllegalArgumentException is thrown.
Solutions
- Use a valid BCP 47 language tag such as en, fr, de-DE
- Validate the tag client-side with Locale.forLanguageTag(tag).getISO3Language() before calling
- Check supported locales against the installed language packs; remove exotic/custom locale codes
Example fix
// before
const locale = 'english'; // invalid
await fetch(`/api/system/index?locale=${locale}`);
// after
const locale = 'en';
await fetch(`/api/system/index?locale=${encodeURIComponent(locale)}`); Defensive patterns
Strategy: validation
Validate before calling
function isBcp47Tag(tag) { try { return Intl.getCanonicalLocales(tag).length > 0; } catch { return false; } }
if (!isBcp47Tag(locale)) throw new Error('invalid language tag'); Type guard
function isValidLocaleTag(tag) { return typeof tag === 'string' && /^[a-zA-Z]{2,3}(-[a-zA-Z0-9]+)*$/.test(tag); } Try / catch
try { await get(`/api/system/index?locale=${locale}`); } catch (e) { if (e.message.includes('BCP47')) { return get('/api/system/index?locale=en'); } throw e; } Prevention
- Always use standard BCP 47 tags (en, fr, de-DE), never language names
- Canonicalize user-provided locales with Intl APIs before sending
- Restrict choices to locales installed on the SonarQube instance
When it happens
Trigger: GET api/system/index with locale values like 'xx', 'qq-US', empty-ish tags, or strings that Locale.forLanguageTag silently maps to an undetermined locale; malformed tags with invalid characters.
Common situations: Passing custom/internal locale codes not in BCP 47; passing language names ('english') instead of tags ('en'); passing locales unsupported by the JVM's CLDR data.
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
- Backup XML is not valid. Root element must be
- Failed to set the New Code Definition. The given value is…
- If branch key is specified, project key needs to be…
- Invalid type
- Page size must be >= 0
AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09).
Data as JSON: /api/errors/453be76fed13e90d.
Report an issue: GitHub.
Appendix: source
Thrown at server/sonar-webserver-webapi/src/main/java/org/sonar/server/platform/ws/IndexAction.java:79
.setDefaultValue(ENGLISH.toLanguageTag());
indexAction.createParam(TS_PARAM)
.setDescription("Date of the last cache update.")
.setExampleValue("2014-06-04T09:31:42+0000");
}
@Override
public void handle(Request request, Response response) throws Exception {
Date timestamp = request.paramAsDateTime(TS_PARAM);
if (timestamp != null && timestamp.after(server.getStartedAt())) {
response.stream().setStatus(HTTP_NOT_MODIFIED).output().close();
return;
}
String localeParam = request.mandatoryParam(LOCALE_PARAM);
Locale locale = Locale.forLanguageTag(localeParam);
try {
checkArgument(!locale.getISO3Language().isEmpty(), INVALID_LANGUAGE_TAG_MESSAGE);
} catch (MissingResourceException e) {
throw new IllegalArgumentException(INVALID_LANGUAGE_TAG_MESSAGE, e);
}
try (JsonWriter json = response.newJsonWriter()) {
json.beginObject();
json.prop("effectiveLocale", i18n.getEffectiveLocale(locale).toLanguageTag());
json.name("messages");
json.beginObject();
i18n.getPropertyKeys().forEach(messageKey -> json.prop(messageKey, i18n.message(locale, messageKey, messageKey)));
json.endObject();
json.endObject();
}
}
}
View on GitHub (pinned to 184c821202)