{"record":{"id":"4a9a842fa7a49f90","repo":"HMCL-dev/HMCL","slug":"too-many-attempts","errorCode":null,"errorMessage":"Too many attempts","messagePattern":"Too many attempts","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"HMCL/src/main/java/org/jackhuang/hmcl/ui/instances/WorldBackupTask.java","lineNumber":68,"sourceCode":"        try (FileChannel lockChannel = needLock ? world.lock() : null) {\n            Files.createDirectories(backupsDir);\n            String time = LocalDateTime.now().format(WorldBackupsPage.TIME_FORMATTER);\n            String baseName = time + \"_\" + world.getFileName();\n            Path backupFile = null;\n            OutputStream outputStream = null;\n\n            int count;\n            for (count = 0; count < 256; count++) {\n                try {\n                    backupFile = backupsDir.resolve(baseName + (count == 0 ? \"\" : \" \" + count) + \".zip\").toAbsolutePath();\n                    outputStream = Files.newOutputStream(backupFile, StandardOpenOption.WRITE, StandardOpenOption.CREATE_NEW);\n                    break;\n                } catch (FileAlreadyExistsException ignored) {\n                }\n            }\n\n            if (outputStream == null)\n                throw new IOException(\"Too many attempts\");\n\n            try (ZipOutputStream zipOutputStream = new ZipOutputStream(new BufferedOutputStream(outputStream))) {\n                String rootName = world.getFileName();\n                Path rootDir = this.world.getFile();\n                Files.walkFileTree(this.world.getFile(), new SimpleFileVisitor<Path>() {\n                    @Override\n                    public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {\n                        if (path.endsWith(\"session.lock\")) {\n                            return FileVisitResult.CONTINUE;\n                        }\n                        zipOutputStream.putNextEntry(new ZipEntry(rootName + \"/\" + rootDir.relativize(path).toString().replace('\\\\', '/')));\n                        Files.copy(path, zipOutputStream);\n                        zipOutputStream.closeEntry();\n                        return FileVisitResult.CONTINUE;\n                    }\n                });\n            }\n","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCL/src/main/java/org/jackhuang/hmcl/ui/instances/WorldBackupTask.java#L50-L86","documentation":"WorldBackupTask.execute tries to create a zip file for a world backup, repeatedly attempting an alternate filename when FileAlreadyExistsException occurs. After exhausting its attempts (the retry loop falls through), outputStream remains null and the task throws IOException(\"Too many attempts\") instead of silently failing. It signals that no free backup filename could be found.","triggerScenarios":"Running a world backup when every candidate output zip filename already exists in the backups directory, so the create-new-file attempt keeps throwing FileAlreadyExistsException until the loop's attempt count is exhausted.","commonSituations":"Backing up a world repeatedly without deleting old backups so the counter-space filenames collide; a backup directory with many stale/partial zip files; clock or counter logic producing the same name each run; read-only or synced (e.g. cloud-synced) backup folders where files reappear.","solutions":["Delete or archive old world backup zips from the backups directory so a free filename is available","Point the backup output to a different/empty directory","Check the backup filename generation (timestamp/counter) for a bug that yields the same name every attempt","Verify write permissions on the backups directory (a persistent failure mode can mask free names)"],"exampleFix":"// before\nif (outputStream == null)\n    throw new IOException(\"Too many attempts\");\n// after\nif (outputStream == null)\n    throw new IOException(\"Too many attempts: could not find a free backup file name in \"\n        + backupDir + \"; please clean up old backups\");","handlingStrategy":"retry","validationCode":"// before backing up\nlong existing = Files.list(backupDir)\n    .filter(p -> p.getFileName().toString().startsWith(worldName))\n    .count();\nif (existing > MAX_ATTEMPTS - 2) {\n    Files.move(oldestBackup, archiveDir.resolve(oldestBackup.getFileName()));\n}","typeGuard":null,"tryCatchPattern":"try {\n    task.execute();\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Too many attempts\")) {\n        cleanOldBackups();\n        retryBackup();\n    } else throw e;\n}","preventionTips":["Schedule periodic cleanup/pruning of old world backups","Use timestamped filenames with millisecond precision to avoid collisions","Monitor backup directory size and alert before it fills with stale zips"],"tags":["io","file-already-exists","backup","java"],"backgroundTag":"file-already-exists","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"}