{"record":{"id":"07a8513f2bce4245","repo":"languagetool-org/languagetool","slug":"sourcelanguage-parameter-missing-must-be-set-w","errorCode":null,"errorMessage":"'sourceLanguage' parameter missing - must be set when 'sourceText' is set","messagePattern":"'sourceLanguage' parameter missing - must be set when 'sourceText' is set","errorType":"validation","errorClass":"BadRequestException","httpStatus":400,"severity":"error","filePath":"languagetool-server/src/main/java/org/languagetool/server/TextChecker.java","lineNumber":905,"sourceCode":"    }\n  }\n\n  private List<CheckResults> getRuleMatches(AnnotatedText aText, Language lang,\n                                         Language motherTongue, Map<String, String> parameters,\n                                         QueryParams params, UserConfig userConfig,\n                                         /*DetectedLanguage detLang,\n                                         List<String> preferredLangs, List<String> preferredVariants,*/\n                                         RuleMatchListener listener) throws Exception {\n    if (cache != null && cache.requestCount() > 0 && cache.requestCount() % CACHE_STATS_PRINT == 0) {\n      String sentenceHitPercentage = String.format(Locale.ENGLISH, \"%.2f\", cache.getSentenceCache().stats().hitRate() * 100.0f);\n      String matchesHitPercentage = String.format(Locale.ENGLISH, \"%.2f\", cache.getMatchesCache().stats().hitRate() * 100.0f);\n      String remoteHitPercentage = String.format(Locale.ENGLISH, \"%.2f\", cache.getRemoteMatchesCache().stats().hitRate() * 100.0f);\n      log.info(\"Cache stats: \" + sentenceHitPercentage + \"% / \" + matchesHitPercentage + \"% / \" + remoteHitPercentage + \"% hit rate\");\n    }\n\n    if (parameters.get(\"sourceText\") != null) {\n      if (parameters.get(\"sourceLanguage\") == null) {\n        throw new BadRequestException(\"'sourceLanguage' parameter missing - must be set when 'sourceText' is set\");\n      }\n      Language sourceLanguage = parseLanguage(parameters.get(\"sourceLanguage\"));\n      JLanguageTool sourceLt = new JLanguageTool(sourceLanguage);\n      JLanguageTool targetLt = new JLanguageTool(lang);\n      if (userConfig.filterDictionaryMatches()) {\n        targetLt.addMatchFilter(new DictionaryMatchFilter(userConfig));\n      }\n      List<BitextRule> bitextRules = Tools.getBitextRules(sourceLanguage, lang);\n      return Collections.singletonList(\n              new CheckResults(Tools.checkBitext(parameters.get(\"sourceText\"), aText.getPlainText(), sourceLt, targetLt, bitextRules), Collections.emptyList())\n      );\n    } else {\n      List<CheckResults> res = new ArrayList<>();\n      res.addAll(getPipelineResults(aText, lang, motherTongue, params, userConfig, listener));\n      return res;\n    }\n  }\n","sourceCodeStart":887,"sourceCodeEnd":923,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-server/src/main/java/org/languagetool/server/TextChecker.java#L887-L923","documentation":"The translation-style sourceText check requires knowing the source language to run the source-side analysis. When 'sourceText' is provided without 'sourceLanguage', the TextChecker constructor throws BadRequestException, since it cannot build the JLanguageTool instance for the source text.","triggerScenarios":"POSTing to /v2/check with sourceText=... but no sourceLanguage parameter (the block at TextChecker.java:905 only creates sourceLt after parseLanguage(sourceLanguage)); also triggered indirectly when sourceLanguage itself is an invalid code (see parseLanguage).","commonSituations":"Clients supporting the sourceText feature sending only the source text; older API wrappers predating the sourceLanguage requirement; copy-pasted examples from plain-check requests extended with sourceText.","solutions":["Add sourceLanguage with a valid short code matching the source text, e.g. sourceLanguage=de-DE","If you have no source text to compare, remove sourceText and just check the target text","Validate client code so sourceText and sourceLanguage are always sent together"],"exampleFix":"// before\ncurl -d text=Hello -d sourceText=Hallo -d language=en-US http://server/v2/check\n// after\ncurl -d text=Hello -d sourceText=Hallo -d sourceLanguage=de-DE -d language=en-US http://server/v2/check","handlingStrategy":"validation","validationCode":"if (params.sourceText != null && !params.sourceLanguage) {\n  throw new Error(\"'sourceLanguage' is required whenever 'sourceText' is set\");\n}","typeGuard":"function sourcePairIsValid(p) {\n  return p.sourceText == null || (typeof p.sourceLanguage === 'string' && p.sourceLanguage.length > 0);\n}","tryCatchPattern":"try {\n  return await check({ ...params });\n} catch (e) {\n  if (e.status === 400 && /'sourceLanguage' parameter missing/.test(e.message)) {\n    throw new Error('Client bug: sourceText sent without sourceLanguage');\n  }\n  throw e;\n}","preventionTips":["Always send sourceText and sourceLanguage as a pair from client code","Detect/deny sourceText submissions when the source language is unknown","Add a schema check (e.g. JSON schema or zod) enforcing the paired fields"],"tags":["http-400","missing-parameter","translation"],"backgroundTag":"missing-required-argument","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}