languagetool-org/languagetool · error · RuntimeException

Language was already instantiated, see the cause stacktrace

Error message

Language was already instantiated, see the cause stacktrace below.

What it means

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.

Source

Thrown at languagetool-language-modules/fr/src/main/java/org/languagetool/language/BelgianFrench.java:32

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301
 * USA
 */
package org.languagetool.language;

import java.util.Collections;
import java.util.List;

public class BelgianFrench extends French {

  private static volatile Throwable instantiationTrace;

  public BelgianFrench() {
    super(true);
    Throwable trace = instantiationTrace;
    if (trace != null) {
      throw new RuntimeException("Language was already instantiated, see the cause stacktrace below.", trace);
    }
    instantiationTrace = new Throwable();
  }

  @Override
  public String getName() {
    return "French (Belgium)";
  }

  @Override
  public String[] getCountries() {
    return new String[] { "BE" };
  }

  @Override
  public List<String> getDefaultDisabledRulesForVariant() {
    List<String> rules = Collections.singletonList("DOUBLER_UNE_CLASSE");
    return rules;

View on GitHub (pinned to 2e990059ce)

Solutions

  1. Remove the direct instantiation and use Languages.getLanguageForShortCode("fr-BE") to get the cached instance.
  2. Inspect the 'cause' stack trace in the exception to find the first instantiation site and eliminate the duplicate path.
  3. If multiple classloaders are involved, consolidate to a single module/classloader loading languagetool-language-modules/fr.

Example fix

// before
Language lang = new BelgianFrench();
// after
Language lang = Languages.getLanguageForShortCode("fr-BE");
Defensive patterns

Strategy: validation

Validate before calling

// Obtain the singleton instead of constructing:
Language lang = Languages.getLanguageForShortCode("fr-BE");

Try / catch

try {
  new BelgianFrench();
} catch (RuntimeException e) {
  e.getCause().printStackTrace(); // shows first instantiation site
}

Prevention

When it happens

Trigger: Calling new BelgianFrench() directly instead of Languages.getLanguageForShortCode("fr-BE")/its getInstance; reflection, serialization, or subclass instantiation creating a second instance.

Common situations: Application code instantiating language objects manually; multiple classloaders each loading the class; frameworks instantiating the class reflectively; test code constructing the language.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of languagetool-org/languagetool@2e990059ce (2026-09-06). Data as JSON: /api/errors/4fd0a31f8d151045. Report an issue: GitHub.