{"record":{"id":"05fc68b6b15f1e02","repo":"languagetool-org/languagetool","slug":"language-was-already-instantiated-see-the-cause-s-05fc68","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/CanadianFrench.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 CanadianFrench extends French {\n\n  private static volatile Throwable instantiationTrace;\n\n  public CanadianFrench() {\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 (Canada)\";\n  }\n\n  @Override\n  public String[] getCountries() {\n    return new String[] { \"CA\" };\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/CanadianFrench.java#L14-L50","documentation":"CanadianFrench's constructor guards against duplicate instantiation of the language object. LT requires language classes to be singletons; the constructor stores a stack trace on the first instantiation and throws RuntimeException carrying that trace when a second instance is created.","triggerScenarios":"Calling new CanadianFrench() directly instead of Languages.getLanguageForShortCode(\"fr-CA\")/getInstance; reflective or framework-driven instantiation; separate classloaders loading the class twice.","commonSituations":"Hand-written code constructing language instances; DI containers scanning and instantiating Language subclasses; plugin systems with isolated classloaders.","solutions":["Use Languages.getLanguageForShortCode(\"fr-CA\") instead of constructing the object.","Follow the cause stack trace to locate and remove the first (illegal) instantiation path.","Ensure only one classloader loads the French language module."],"exampleFix":"// before\nLanguage lang = new CanadianFrench();\n// after\nLanguage lang = Languages.getLanguageForShortCode(\"fr-CA\");","handlingStrategy":"validation","validationCode":"// Obtain the singleton instead of constructing:\nLanguage lang = Languages.getLanguageForShortCode(\"fr-CA\");","typeGuard":null,"tryCatchPattern":"try {\n  new CanadianFrench();\n} catch (RuntimeException e) {\n  e.getCause().printStackTrace(); // shows first instantiation site\n}","preventionTips":["Use the language registry, not constructors, for Language objects","Keep LanguageTool on a single classloader","Audit DI/serialization frameworks that reflectively instantiate classes"],"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"}