languagetool-org/languagetool · error · BadRequestException
{e.getMessage()} (invalid language code passed to Languages.
Error message
{e.getMessage()} (invalid language code passed to Languages.getLanguageForShortCode) What it means
LanguageTool's server wraps the IllegalArgumentException thrown by Languages.getLanguageForShortCode when a request's 'language' (or related) parameter is not a recognized language/variant short code. It is re-thrown as a BadRequestException with HTTP 400 semantics, so the caller sent an unsupported language identifier.
Source
Thrown at languagetool-server/src/main/java/org/languagetool/server/TextChecker.java:265
long start = System.currentTimeMillis();
prewarmPipelinePool();
long end = System.currentTimeMillis();
log.info("Prewarming finished in {} seconds.", (end - start) / 1000.0);
}
if (config.getAbTest() != null) {
UserConfig.enableABTests();
log.info("A/B-Test enabled: " + config.getAbTest());
if (config.getAbTest().equals("SuggestionsOrderer")) {
SuggestionsOrdererConfig.setMLSuggestionsOrderingEnabled(true);
}
}
}
protected static Language parseLanguage(String code) throws BadRequestException {
try {
return Languages.getLanguageForShortCode(code);
} catch (IllegalArgumentException e) {
throw new BadRequestException(e.getMessage());
}
}
/**
* Hash a string deterministically into a 64-bit signed long; use textSessionIdParam if set, fall back to client IP.
*/
protected static Long computeTextSessionID(String textSessionIdParam, String ip) {
String input = textSessionIdParam != null ? textSessionIdParam : ip;
if (input == null) {
return null;
}
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] bytes = md.digest(input.getBytes(StandardCharsets.UTF_8));
ByteBuffer buffer = ByteBuffer.wrap(bytes);
Long textSessionId = buffer.getLong();
return textSessionId;View on GitHub (pinned to 2e990059ce)
Solutions
- Check the code against Languages.getLanguageForShortCode / the server's supported language list (GET /v2/languages)
- Use the exact short code including the variant, e.g. 'en-US', 'pt-BR', not just 'en' or a display name
- Trim whitespace and URL-encode the language parameter correctly in the HTTP request
- If the language truly is missing, build/register a language module or use a close existing variant
Example fix
// before POST /v2/check language=english // after POST /v2/check language=en-US
Defensive patterns
Strategy: validation
Validate before calling
const SUPPORTED = await fetch(baseUrl + '/v2/languages').then(r => r.json());
function isValidLangCode(code) {
return SUPPORTED.some(l => l.code === code || code.startsWith(l.code + '-'));
}
if (!isValidLangCode(params.language)) throw new Error(`Unsupported language code: ${params.language}`); Type guard
function isLangCode(v) {
return typeof v === 'string' && /^[a-z]{2,3}(-[A-Z]{2}|-[a-z]{2,4})?$/.test(v.trim());
} Try / catch
try {
const res = await check(text, lang);
} catch (e) {
if (e.status === 400 && /invalid language/i.test(e.message)) {
lang = 'en-US'; // fallback to a known-supported code
} else throw e;
} Prevention
- Fetch /v2/languages once and validate codes against it
- Always use full variant codes like en-US when variants exist
- Trim and URL-encode the language parameter
- Pin client and server LanguageTool versions so language sets match
When it happens
Trigger: Passing an unknown or malformed code to the /v2/check endpoint's language, motherTongue, altLanguages, sourceLanguage parameters, or language=auto variant parameters, e.g. language='xx' or 'english' instead of 'en-US'. Also thrown via parseLanguage from getLanguageVariantForCode and detectLanguageOfString paths.
Common situations: Typos in the language code, using a display name instead of a code, requesting a language variant that is not registered in the server build, or a client built for a newer LanguageTool version requesting a language the server does not support.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Text checking was stopped due to too many errors (more than
- Format error in file ${path}, line: ${line}
- No IssueType found for name '" + name + "'. Valid values: "
- The number of forms and postags has to be the same in disamb
- Set 'no', 'regexp' and 'postag_regexp' for filter PartialPos
AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06).
Data as JSON: /api/errors/154741eda3af0341.
Report an issue: GitHub.