{"record":{"id":"01a473d522ac78fa","repo":"HMCL-dev/HMCL","slug":"failed-to-close-session-lock-channel-of-the-world","errorCode":null,"errorMessage":"Failed to close session lock channel of the world ","messagePattern":"Failed to close session lock channel of the world ","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/instances/WorldManageUIUtils.java","lineNumber":127,"sourceCode":"                            ).whenComplete(Schedulers.javafx(), (throwable) -> {\n                                if (throwable == null) {\n                                    handler.resolve();\n                                } else {\n                                    handler.reject(i18n(\"world.duplicate.failed\"));\n                                    LOG.warning(\"Failed to duplicate world \" + world.getFile(), throwable);\n                                }\n                            })\n                            .start();\n                }, \"\", new RequiredValidator(), new Validator(i18n(\"world.duplicate.failed.invalid_name\"), FileUtils::isNameValid));\n    }\n\n    public static void closeSessionLockChannel(World world, FileChannel sessionLockChannel) throws IOException {\n        if (sessionLockChannel != null) {\n            try {\n                sessionLockChannel.close();\n                LOG.info(\"Closed session lock channel of the world \" + world.getFileName());\n            } catch (IOException e) {\n                throw new IOException(\"Failed to close session lock channel of the world \" + world.getFile(), e);\n            }\n        }\n    }\n\n    public static FileChannel getSessionLockChannel(World world) {\n        try {\n            FileChannel lock = world.lock();\n            LOG.info(\"Acquired lock on world \" + world.getFileName());\n            return lock;\n        } catch (WorldLockedException ignored) {\n            return null;\n        }\n    }\n\n}\n","sourceCodeStart":109,"sourceCodeEnd":143,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/instances/WorldManageUIUtils.java#L109-L143","documentation":"WorldManageUIUtils.closeSessionLockChannel closes a world's session.lock FileChannel and wraps any IOException from close() in a new IOException prefixed with \"Failed to close session lock channel of the world \". Note the message string concatenates world.getFile() (the path) even though the log line uses getFileName(). It indicates the lock channel could not be released, which usually means the OS-level close failed.","triggerScenarios":"Called from World deletion or export flows after getSessionLockChannel opened a session.lock file; the FileChannel.close() call throws IOException (e.g. the underlying file descriptor is in a bad state or the filesystem errors on close).","commonSituations":"Deleting/exporting a Minecraft world on Windows while another process holds the lock; antivirus or backup software interfering with file handles; network or FAT/exFAT filesystems with flaky close semantics; a previous double-close leaving the channel invalid.","solutions":["Retry the delete/export operation after ensuring no other process (game, editor, sync client) is touching the world folder","Check the chained cause (e.getCause()) to identify the real OS/filesystem error","If developing, log-and-continue may be acceptable since close() failures are often benign — consider not failing the whole operation","Run disk/antivirus exclusion checks on the .minecraft/saves directory"],"exampleFix":"// before\nthrow new IOException(\"Failed to close session lock channel of the world \" + world.getFile(), e);\n// after\ntry {\n    sessionLockChannel.close();\n} catch (IOException e) {\n    LOG.warning(\"Failed to close session lock channel of the world \" + world.getFile(), e);\n    // non-fatal: proceed with delete/export\n}","handlingStrategy":"try-catch","validationCode":"// before delete/export\nif (Files.exists(worldDir.resolve(\"session.lock\"))) {\n    try (FileChannel ignored = FileChannel.open(worldDir.resolve(\"session.lock\"), WRITE, CREATE_NEW)) {\n        // if this succeeds no other process holds an OS lock\n    } catch (IOException e) {\n        throw new IllegalStateException(\"World in use by another process\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    WorldManageUIUtils.delete(world);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Failed to close session lock channel\")) {\n        LOG.warning(\"Non-fatal lock close failure\", e); // proceed or retry\n    } else throw e;\n}","preventionTips":["Close the game and world-editing tools before deleting/exporting worlds","Exclude .minecraft/saves from antivirus real-time scanning and cloud sync","Treat close() failures on lock channels as non-fatal and log them instead of aborting"],"tags":["io","file-lock","resource-cleanup","java"],"backgroundTag":"file-open-failed","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}