{"record":{"id":"4fd0a31f8d151045","repo":"languagetool-org/languagetool","slug":"language-was-already-instantiated-see-the-cause-s-4fd0a3","errorCode":null,"errorMessage":"Language was already instantiated, see the cause stacktrace below.","messagePattern":"Language was already instantiated, see the cause stacktrace below\\.","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"languagetool-language-modules/fr/src/main/java/org/languagetool/language/BelgianFrench.java","lineNumber":32,"sourceCode":" * You should have received a copy of the GNU Lesser General Public\n * License along with this library; if not, write to the Free Software\n * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301\n * USA\n */\npackage org.languagetool.language;\n\nimport java.util.Collections;\nimport java.util.List;\n\npublic class BelgianFrench extends French {\n\n  private static volatile Throwable instantiationTrace;\n\n  public BelgianFrench() {\n    super(true);\n    Throwable trace = instantiationTrace;\n    if (trace != null) {\n      throw new RuntimeException(\"Language was already instantiated, see the cause stacktrace below.\", trace);\n    }\n    instantiationTrace = new Throwable();\n  }\n\n  @Override\n  public String getName() {\n    return \"French (Belgium)\";\n  }\n\n  @Override\n  public String[] getCountries() {\n    return new String[] { \"BE\" };\n  }\n\n  @Override\n  public List<String> getDefaultDisabledRulesForVariant() {\n    List<String> rules = Collections.singletonList(\"DOUBLER_UNE_CLASSE\");\n    return rules;","sourceCodeStart":14,"sourceCodeEnd":50,"githubUrl":"https://github.com/languagetool-org/languagetool/blob/2e990059ce67d5e2a0f7f7ca5d31160c6709df4b/languagetool-language-modules/fr/src/main/java/org/languagetool/language/BelgianFrench.java#L14-L50","documentation":"BelgianFrench's constructor is a debugging guard: Language subclasses may be instantiated only once (LT caches instances via getInstance/languages registry). The constructor records a stack trace on first instantiation and throws RuntimeException with that trace as cause on any second instantiation, exposing who created the duplicate.","triggerScenarios":"Calling new BelgianFrench() directly instead of Languages.getLanguageForShortCode(\"fr-BE\")/its getInstance; reflection, serialization, or subclass instantiation creating a second instance.","commonSituations":"Application code instantiating language objects manually; multiple classloaders each loading the class; frameworks instantiating the class reflectively; test code constructing the language.","solutions":["Remove the direct instantiation and use Languages.getLanguageForShortCode(\"fr-BE\") to get the cached instance.","Inspect the 'cause' stack trace in the exception to find the first instantiation site and eliminate the duplicate path.","If multiple classloaders are involved, consolidate to a single module/classloader loading languagetool-language-modules/fr."],"exampleFix":"// before\nLanguage lang = new BelgianFrench();\n// after\nLanguage lang = Languages.getLanguageForShortCode(\"fr-BE\");","handlingStrategy":"validation","validationCode":"// Obtain the singleton instead of constructing:\nLanguage lang = Languages.getLanguageForShortCode(\"fr-BE\");","typeGuard":null,"tryCatchPattern":"try {\n  new BelgianFrench();\n} catch (RuntimeException e) {\n  e.getCause().printStackTrace(); // shows first instantiation site\n}","preventionTips":["Never call 'new' on Language subclasses; always use Languages.getLanguageForShortCode","Check the cause stack trace to find the duplicate instantiation path","Avoid multiple classloaders for LanguageTool modules"],"tags":["java","languagetool","singleton","instantiation"],"backgroundTag":"invalid-state-transition","analyzedSha":"2e990059ce67d5e2a0f7f7ca5d31160c6709df4b","analyzedAt":"2026-09-06T09:20:17.015Z","contentChangedAt":"2026-09-06T09:20:17.015Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}