HMCL-dev/HMCL · error · IOException

Not a valid world directory

Error message

Not a valid world directory

What it means

Thrown by World.rename(String) when the world's underlying file field is not a directory. Rename only works on extracted world folders because it rewrites LevelName in level.dat and then renames the folder; a zip-backed World cannot be renamed this way.

Solutions

  1. Call install(savesDir, name) on the zip-backed world first, then rename the installed world directory
  2. Ensure the World was constructed from a directory that still exists (Files.isDirectory)
  3. Re-create the World object if the folder was moved or deleted

Example fix

// before
World world = new World(Path.of("world.zip"));
world.rename("NewName"); // throws: not a directory
// after
World world = new World(Path.of("world.zip"));
world.install(Path.of(".minecraft/saves"), "OldName");
World installed = new World(Path.of(".minecraft/saves/OldName"));
installed.rename("NewName");
Defensive patterns

Strategy: try-catch

Validate before calling

if (!Files.isDirectory(world.getFile())) throw new IllegalStateException("rename requires an installed (directory) world");

Type guard

static boolean isRenamable(World w) {
    return Files.isDirectory(w.getFile());
}

Try / catch

try {
    world.rename(newName);
} catch (IOException e) {
    if (String.valueOf(e.getMessage()).equals("Not a valid world directory")) {
        // install the world into saves first, then rename
    }
}

Prevention

When it happens

Trigger: Calling world.rename("NewName") on a World constructed from a zip file, or after the world directory was deleted/moved before the call.

Common situations: Renaming a world imported from a zip before it was installed to a saves directory, renaming after manually deleting the folder, or passing a file path instead of a directory to the World constructor.

Related errors


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

Appendix: source

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

        this.worldGenSettingsDataPath = worldGenSettingsDataPath;
        this.worldGenSettingsDataBackingTag = worldGenSettingsDataBackingTag;
        this.normalizedWorldGenSettingsData = unifiedWorldGenSettingsData;
    }

    private void setPlayerData(Path playerDataPath, CompoundTag playerData) {
        this.playerDataPath = playerDataPath;
        this.playerData = playerData;
    }

    public void reloadWorldData() throws IOException {
        loadAndCheckWorldData();
    }

    // The rename method is used to rename temporary world object during installation and copying,
    // so there is no need to modify the `file` field.
    public void rename(String newName) throws IOException {
        if (!Files.isDirectory(file))
            throw new IOException("Not a valid world directory");

        // Change the name recorded in level.dat
        dataTag.setString("LevelName", newName);
        writeLevelData();

        // then change the folder's name
        Files.move(file, file.resolveSibling(newName));
    }

    public void install(Path savesDir, String name) throws IOException {
        Path worldDir;
        try {
            worldDir = savesDir.resolve(name);
        } catch (InvalidPathException e) {
            throw new IOException(e);
        }

        if (Files.isDirectory(worldDir)) {

View on GitHub (pinned to 24702dc5a0)