{"record":{"id":"a8f3873264d0ee73","repo":"elastic/elasticsearch","slug":"failed-to-create-hard-link-pointing-to","errorCode":null,"errorMessage":"Failed to create hard link {} pointing to {}","messagePattern":"Failed to create hard link (.+?) pointing to (.+?)","errorType":"exception","errorClass":"LinkCreationException","httpStatus":null,"severity":"error","filePath":"build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java","lineNumber":1329,"sourceCode":"            }\n        }\n    }\n\n    /**\n     * Does the equivalent of `cp -lr` and `chmod -r a-w` to save space and improve speed.\n     * We remove write permissions to make sure files are note mistakenly edited ( e.x. the config file ) and changes\n     * reflected across all copies. Permissions are retained to be able to replace the links.\n     *\n     * @param sourceRoot      where to copy from\n     * @param destinationRoot destination to link to\n     */\n    private void syncWithLinks(Path sourceRoot, Path destinationRoot) {\n        sync(sourceRoot, destinationRoot, (Path d, Path s) -> {\n            try {\n                Files.createLink(d, s);\n            } catch (IOException e) {\n                // Note does not work for network drives, e.g. Vagrant\n                throw new LinkCreationException(\"Failed to create hard link \" + d + \" pointing to \" + s, e);\n            }\n        });\n    }\n\n    private void syncWithCopy(Path sourceRoot, Path destinationRoot) {\n        sync(sourceRoot, destinationRoot, (Path d, Path s) -> {\n            try {\n                Files.copy(s, d);\n            } catch (IOException e) {\n                throw new UncheckedIOException(\"Failed to copy \" + s + \" to \" + d, e);\n            }\n        });\n    }\n\n    private void sync(Path sourceRoot, Path destinationRoot, BiConsumer<Path, Path> syncMethod) {\n        assert Files.exists(destinationRoot) == false;\n        try {\n            Files.walkFileTree(sourceRoot, new SimpleFileVisitor<>() {","sourceCodeStart":1311,"sourceCodeEnd":1347,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools/src/main/java/org/elasticsearch/gradle/testclusters/ElasticsearchNode.java#L1311-L1347","documentation":"Thrown by syncWithLinks when Files.createLink(d, s) fails with IOException. The plugin uses hard links to share the extracted distribution across multiple nodes without duplicating files (saves disk + keeps config immutable). The comment notes this does not work for network drives (e.g. Vagrant shared folders).","triggerScenarios":"Files.createLink throws when: the source and destination are on different filesystems/volumes (EXDEV), the filesystem does not support hard links (some network filesystems, FAT/exFAT, some FUSE mounts), the destination already exists, or permissions are insufficient.","commonSituations":"The gradle build dir lives on a network share (NFS, SMB, Vagrant synced folder, Docker volume on a non-native driver). The user moved their gradle home or project onto a separate volume from the extracted distro.","solutions":["Move the project and gradle home (GRADLE_USER_HOME) onto a local filesystem that supports hard links (ext4, APFS, NTFS).","If on a Mac with a case-insensitive volume or an external drive, build from the internal SSD.","For Vagrant/Docker, use a native synced-folder type (rsync/nfs vs virtualbox shared), or build outside the shared folder.","If you cannot change the filesystem, you must not use this code path — file an issue; there is no in-process fallback to copy."],"exampleFix":"// before: workingDir on a network share\n// gradle.properties:\n//   gradle.userHomeDir=/network/share/gradle-home\n// after: point gradle home at local disk\n//   gradle.userHomeDir=/Users/me/.gradle","handlingStrategy":"validation","validationCode":"try {\n    Files.createLink(Path.of(\"probe-link\"), Path.of(\"probe-target\"));\n    Files.deleteIfExists(Path.of(\"probe-link\"));\n} catch (IOException e) {\n    // filesystem does not support hard links — fail fast with a clear message\n}","typeGuard":null,"tryCatchPattern":"try {\n    Files.createLink(d, s);\n} catch (IOException e) {\n    throw new LinkCreationException(\"Failed to create hard link \" + d + \" pointing to \" + s, e);\n}","preventionTips":["Keep the gradle project and gradle home on a local filesystem that supports hard links.","Avoid Vagrant/Docker non-native synced folders for the build dir.","Do not split the distro cache and the working dir across volumes."],"tags":["testclusters","hardlink","filesystem","network-drive"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}