{"record":{"id":"bd1873f5edffc3d9","repo":"elastic/elasticsearch","slug":"found-invalid-file-permissions","errorCode":null,"errorMessage":"Found invalid file permissions:\n{}","messagePattern":"Found invalid file permissions:\n(.+?)","errorType":"exception","errorClass":"GradleException","httpStatus":null,"severity":"error","filePath":"build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/FilePermissionsTask.java","lineNumber":106,"sourceCode":"            .stream()\n            .map(sourceTree -> sourceTree.matching(filesFilter))\n            .reduce(FileTree::plus)\n            .orElse(projectLayout.files().getAsFileTree());\n    }\n\n    @TaskAction\n    public void checkInvalidPermissions() throws IOException {\n        if (OS.current() == OS.WINDOWS) {\n            throw new StopExecutionException();\n        }\n        List<String> failures = getFiles().getFiles()\n            .stream()\n            .filter(FilePermissionsTask::isExecutableFile)\n            .map(file -> \"Source file is executable: \" + file)\n            .collect(Collectors.toList());\n\n        if (failures.isEmpty() == false) {\n            throw new GradleException(\"Found invalid file permissions:\\n\" + String.join(\"\\n\", failures));\n        }\n\n        outputMarker.getParentFile().mkdirs();\n        Files.writeString(outputMarker.toPath(), \"done\");\n    }\n\n    @OutputFile\n    public File getOutputMarker() {\n        return outputMarker;\n    }\n\n    @Internal\n    public abstract ListProperty<FileTree> getSources();\n}\n","sourceCodeStart":88,"sourceCodeEnd":121,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/precommit/FilePermissionsTask.java#L88-L121","documentation":"The intended result of FilePermissionsTask: one or more source files have an executable bit set (OWNER/GROUP/OTHERS_EXECUTE). Java source files must not be executable; the task fails the build listing each offending file. It is a hygiene check, not an infrastructure fault.","triggerScenarios":"Any file under getSources() has at least one execute permission bit set, detected via POSIX readAttributes. Skipped entirely on Windows (StopExecutionException).","commonSituations":"A script accidentally chmod +x'd a .java file; files copied from a Windows zip with all-bits-set; a CI image that sets executable bits; running chmod -R +x on the repo by mistake.","solutions":["Remove the executable bit from every listed file: chmod -x <each listed file>.","Bulk-fix the repo: git ls-files -z '*.java' | xargs -0 chmod -x, then commit.","Find what set the bit (a hook, an editor, a packaging step) to prevent recurrence.","Re-run the filePermissions task to confirm clean."],"exampleFix":"# before: src/main/java/Foo.java has mode 0755\n# after\nchmod -x src/main/java/Foo.java   # now 0644","handlingStrategy":"validation","validationCode":"// Pre-build hook: fail fast listing any executable source files before the task runs\ntry (Stream<Path> s = Files.walk(Path.of(\"src\"))) {\n    List<Path> exec = s.filter(Files::isRegularFile)\n        .filter(p -> Files.isExecutable(p))\n        .toList();\n    if (!exec.isEmpty()) throw new IllegalStateException(\"Executable source files: \" + exec);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never run blanket chmod +x on the repo.","Add a pre-commit git hook that rejects executable .java/.kt files.","On Windows zip extraction, normalise bits before committing."],"tags":["gradle","file-permissions","precommit","posix","code-quality"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T11:17:21.771Z"}