{"record":{"id":"60a6ec96e7612eb8","repo":"languagetool-org/languagetool","slug":"french-premium-language-expected-got-languag","errorCode":null,"errorMessage":"French(Premium) language expected, got \" + language","messagePattern":"French\\(Premium\\) language expected, got \" \\+ language","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-language-modules/fr/src/main/java/org/languagetool/language/French.java","lineNumber":599,"sourceCode":"    if (enabledRules != null && enabledRules.contains(\"APOS_TYP\")) {\n      List<String> newReplacements = new ArrayList<>();\n      for (String s : rm.getSuggestedReplacements()) {\n        if (s.length() > 1) {\n          s = s.replace('\\'', '’');\n        }\n        newReplacements.add(s);\n      }\n      rm.setSuggestedReplacements(newReplacements);\n    }\n    return rm;\n  }\n\n  public static @NotNull French getInstance() {\n    Language language = Objects.requireNonNull(Languages.getLanguageForShortCode(FRENCH_SHORT_CODE));\n    if (language instanceof French french) { // cannot use French here as in premium FRENCH_SHORT_CODE returns FrenchPremium\n      return french;\n    }\n    throw new RuntimeException(\"French(Premium) language expected, got \" + language);\n  }\n}","sourceCodeStart":581,"sourceCodeEnd":601,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-language-modules/fr/src/main/java/org/languagetool/language/French.java#L581-L601","documentation":"French.getInstance() resolves the language for the French short code and asserts it is an instance of French. In the premium build the short code maps to FrenchPremium (a subclass), so the instanceof check accepts it; if Languages returns any other Language implementation, the invariant is broken and RuntimeException is thrown.","triggerScenarios":"Calling French.getInstance() when the language registry contains a non-French implementation for 'fr' — e.g. a custom Language registered under the 'fr' short code, or a classpath mixing language modules so the registry resolution is unexpected.","commonSituations":"Registering a custom French-like language with short code 'fr'; shading/repackaging LanguageTool classes so Languages.getLanguageForShortCode returns an unexpected class; premium vs standard module conflicts on the classpath.","solutions":["Check the 'got <language>' value in the message to see which class was registered for 'fr'.","Remove/rename any custom Language registered under the 'fr' short code.","Clean the classpath of duplicate/mixed languagetool-language-modules jars (standard vs premium)."],"exampleFix":"// before (custom registration hijacks the code)\nLanguages.addLanguage(new MyFrenchVariant()); // short code \"fr\"\n// after\nLanguages.addLanguage(new MyFrenchVariant()); // short code \"fr-XX\"","handlingStrategy":"validation","validationCode":"Language l = Languages.getLanguageForShortCode(\"fr\");\nif (!(l instanceof French)) {\n  throw new IllegalStateException(\"'fr' is bound to \" + l.getClass() + \", not French/FrenchPremium\");\n}","typeGuard":"boolean isFrench(Language l) { return l instanceof French; }","tryCatchPattern":"try {\n  French french = French.getInstance();\n} catch (RuntimeException e) {\n  LOG.error(\"'fr' short code bound to unexpected language: {}\", e.getMessage());\n}","preventionTips":["Never register custom languages under the reserved 'fr' short code","Keep standard and premium LanguageTool jars from mixing on the classpath","Log Languages.getLanguageForShortCode(\"fr\").getClass() when debugging registry issues"],"tags":["java","languagetool","singleton","registry"],"backgroundTag":"invalid-argument-value","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"}