Grasscutters/Grasscutter · critical · RuntimeException

Unable to load the primary, fallback, and 'en-US' language f

Error message

Unable to load the primary, fallback, and 'en-US' language files.

What it means

Language.getLanguageTextMapKey / load logic tries the requested language file, then a fallback, then the bundled /languages/en-US.json; if the en-US resource stream is also null, it throws this RuntimeException. This means the language resource files are not on the classpath at all — a broken installation, not a bad user config.

Source

Thrown at src/main/java/emu/grasscutter/utils/lang/Language.java:218

                return new LanguageStreamDescription(actualLanguageCode, null);
            }

            file = Grasscutter.class.getResourceAsStream("/languages/" + fallback);
        }

        if (file == null) { // Fallback the fallback language.
            Grasscutter.getLogger()
                    .warn("Failed to load language file: " + fallback + ", falling back to: en-US.json");
            actualLanguageCode = "en-US";
            if (cachedLanguages.containsKey(actualLanguageCode)) {
                return new LanguageStreamDescription(actualLanguageCode, null);
            }

            file = Grasscutter.class.getResourceAsStream("/languages/en-US.json");
        }

        if (file == null)
            throw new RuntimeException(
                    "Unable to load the primary, fallback, and 'en-US' language files.");

        return new LanguageStreamDescription(actualLanguageCode, file);
    }

    private static Int2ObjectMap<String> loadTextMapFile(String language, IntSet nameHashes) {
        Int2ObjectMap<String> output = new Int2ObjectOpenHashMap<>();
        try (BufferedReader file =
                Files.newBufferedReader(
                        getResourcePath("TextMap/TextMap" + language + ".json"), StandardCharsets.UTF_8)) {
            Matcher matcher = textMapKeyValueRegex.matcher("");
            return new Int2ObjectOpenHashMap<>(
                    file.lines()
                            .sequential()
                            .map(matcher::reset) // Side effects, but it's faster than making a new one
                            .filter(Matcher::find)
                            .filter(
                                    m ->

View on GitHub (pinned to f373827a83)

Solutions

  1. Rebuild the project so resources are packaged: run the gradle build (e.g. ./gradlew build) and launch the produced jar
  2. Verify src/main/resources/languages/en-US.json exists in the repo and inside the jar (jar tf grasscutter.jar | grep languages)
  3. If running from an IDE/exploded classpath, ensure src/main/resources is marked as a resources root
  4. Check any -DlanguageCode or config language value is not the root cause, though fixing the classpath is the real fix

Example fix

// before (launching bare classes without resources on classpath)
java -cp classes emu.grasscutter.Grasscutter
// after
./gradlew build && java -jar grasscutter.jar
Defensive patterns

Strategy: fallback

Validate before calling

boolean languageResourcesPresent() {
  return Grasscutter.class.getResource("/languages/en-US.json") != null;
}

Type guard

null

Try / catch

try {
  Language lang = Language.load("en-US");
} catch (RuntimeException e) {
  logger.fatal("Language resources missing from classpath; rebuild the jar.");
  System.exit(1);
}

Prevention

When it happens

Trigger: Calling Language.load/getTextMap (or starting Grasscutter) when none of the requested language, fallback, and embedded en-US.json resources resolve, i.e. Grasscutter.class.getResourceAsStream("/languages/en-US.json") returns null.

Common situations: Running from a partially built jar where resources weren't packaged; deleting or renaming src/main/resources/languages; launching classes without the resources directory on the classpath; corrupted gradle build output.

Related errors


AI-assisted analysis of Grasscutters/Grasscutter@f373827a83 (2026-09-03). Data as JSON: /api/errors/8e716155a486939e. Report an issue: GitHub.