HMCL-dev/HMCL · error · IOException

level.dat missing LevelName

Error message

level.dat missing LevelName

What it means

Thrown by loadAndCheckLevelData when level.dat contains the Data compound but its 'LevelName' entry is missing or not a StringTag. HMCL uses LevelName as the display name of the world, so it treats its absence as an invalid world.

Solutions

  1. Add or repair Data.LevelName as a string tag using an NBT editor (e.g. NBTExplorer)
  2. Restore level.dat from a backup
  3. Re-export/re-copy the world from the original Minecraft instance
  4. If writing test worlds, include Data.LevelName as a StringTag

Example fix

// before (NBT fixture)
compound.put("Data", dataTag); // dataTag has no LevelName
// after
dataTag.putString("LevelName", "My World");
compound.put("Data", dataTag);
Defensive patterns

Strategy: try-catch

Try / catch

try {
    World world = new World(worldDir);
} catch (IOException e) {
    if (String.valueOf(e.getMessage()).equals("level.dat missing LevelName")) {
        // fix via NBT editor or fall back to using the folder name as display name
    }
}

Prevention

When it happens

Trigger: new World(worldDir) on a level.dat whose Data compound lacks LevelName or stores it as a non-string tag type.

Common situations: level.dat edited incorrectly with an NBT editor deleting LevelName, worlds exported by third-party tools that strip metadata, partially corrupted Data compounds, or custom test fixtures that omit the field.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of HMCL-dev/HMCL@24702dc5a0 (2026-09-10). Data as JSON: /api/errors/abe1b9d61cb99ff3. Report an issue: GitHub.

Appendix: source

Thrown at HMCLCore/src/main/java/org/jackhuang/hmcl/game/World.java:250

        return getGameVersion() != null && getGameVersion().isAtLeast("1.20", "23w14a");
    }

    public static boolean supportQuickPlay(GameVersionNumber gameVersionNumber) {
        return gameVersionNumber != null && gameVersionNumber.isAtLeast("1.20", "23w14a");
    }

    private void loadAndCheckWorldData() throws IOException {
        loadAndCheckLevelData(levelDataPath);
        loadOtherData();
    }

    private void loadAndCheckLevelData(Path levelDat) throws IOException {
        this.levelData = NBTCodec.of().readTag(levelDat, TagType.COMPOUND);
        if (!(levelData.get("Data") instanceof CompoundTag data))
            throw new IOException("level.dat missing Data");

        if (!(data.get("LevelName") instanceof StringTag))
            throw new IOException("level.dat missing LevelName");

        if (!(data.get("LastPlayed") instanceof LongTag))
            throw new IOException("level.dat missing LastPlayed");
        this.dataTag = data;
    }

    private void loadOtherData() throws IOException {
        if (!(levelData.get("Data") instanceof CompoundTag data)) return;

        Path worldGenSettingsDatPath = file.resolve("data/minecraft/world_gen_settings.dat");
        if (data.get("WorldGenSettings") instanceof CompoundTag worldGenSettingsTag) {
            setWorldGenSettingsData(null, worldGenSettingsTag, worldGenSettingsTag);
        } else if (Files.isRegularFile(worldGenSettingsDatPath)) {
            CompoundTag raw = NBTCodec.of().readTag(worldGenSettingsDatPath, TagType.COMPOUND);
            if (raw.get("data") instanceof CompoundTag compoundTag) {
                setWorldGenSettingsData(worldGenSettingsDatPath, raw, compoundTag);
            } else {
                setWorldGenSettingsData(null, null, null);

View on GitHub (pinned to 24702dc5a0)