{"record":{"id":"adb68a5d263dab2b","repo":"HMCL-dev/HMCL","slug":"zip-entry-has-an-invalid-symlink-target","errorCode":null,"errorMessage":"Zip entry has an invalid symlink target: ","messagePattern":"Zip entry has an invalid symlink target: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Unzipper.java","lineNumber":129,"sourceCode":"                    continue;\n                }\n\n                entryCount++;\n\n                if (entry.isDirectory()) {\n                    Files.createDirectories(destFile);\n                } else {\n                    Files.createDirectories(destFile.getParent());\n                    if (entry.isUnixSymlink()) {\n                        String linkTarget = reader.getUnixSymlink(entry);\n                        if (replaceExistentFile)\n                            Files.deleteIfExists(destFile);\n\n                        Path targetPath;\n                        try {\n                            targetPath = Path.of(linkTarget);\n                        } catch (InvalidPathException e) {\n                            throw new IOException(\"Zip entry has an invalid symlink target: \" + entry.getName(), e);\n                        }\n\n                        if (!destFile.getParent().resolve(targetPath).toAbsolutePath().normalize().startsWith(destDir)) {\n                            throw new IOException(\"Zip entry is trying to create a symlink outside of the destination directory: \" + entry.getName());\n                        }\n\n                        try {\n                            Files.createSymbolicLink(destFile, targetPath);\n                        } catch (FileAlreadyExistsException ignored) {\n                        }\n                    } else {\n                        try (InputStream input = reader.getInputStream(entry)) {\n                            Files.copy(input, destFile, copyOptions);\n                        } catch (FileAlreadyExistsException e) {\n                            if (replaceExistentFile)\n                                throw e;\n                        }\n","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/HMCL-dev/HMCL/blob/24702dc5a0214034f4c27166d5fd30cad08cec19/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Unzipper.java#L111-L147","documentation":"When an archive entry is a symbolic link, Unzipper parses its target string with Path.of; if the target is not a valid path (invalid characters, null bytes, empty), the InvalidPathException is wrapped in an IOException naming the entry.","triggerScenarios":"Extracting archives whose symlink entries contain targets with illegal path characters (e.g. NUL bytes, reserved Windows characters like ':' or '?'), or malformed/empty link targets.","commonSituations":"Unix-authored archives containing symlinks with unusual targets extracted on Windows; archives corrupted or hand-edited; packaging tools emitting non-portable symlink entries.","solutions":["Remove or fix the invalid symlink entries in the archive before distribution","Skip symlink entries when extracting on platforms that cannot represent them","Repackage the archive with relative, portable link targets","Re-download the archive in case of corruption"],"exampleFix":"// before\n// archive entry: link -> 'C:\\bad:target' (illegal on Windows)\n// after\n// repackage with: ln -s ../../lib/shared.so link","handlingStrategy":"validation","validationCode":"// pre-scan symlink entries\ntry (ZipFile zf = new ZipFile(zip)) {\n    for (ZipEntry e : Collections.list(zf.entries())) {\n        if (isSymlinkEntry(e)) {\n            String target = readLinkTarget(zf, e);\n            try { Path.of(target); } catch (InvalidPathException ex) {\n                throw new IOException(\"invalid symlink target: \" + e.getName());\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    unzipper.unzip();\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Zip entry has an invalid symlink target\")) {\n        // skip or repack the archive without symlinks\n    } else throw e;\n}","preventionTips":["Package archives without platform-specific symlinks when possible","Use relative, portable link targets","Validate archives from Unix build machines before Windows distribution","Re-download corrupted archives instead of hand-editing"],"tags":["io","zip","symlink"],"backgroundTag":"invalid-argument-format","analyzedSha":"24702dc5a0214034f4c27166d5fd30cad08cec19","analyzedAt":"2026-09-10T12:36:46.680Z","contentChangedAt":"2026-09-10T12:36:46.680Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}