quarkusio/quarkus · error · CodeGenException

Failed to make the file executable: ${exe}

Error message

Failed to make the file executable: ${exe}

What it means

Quarkus copies the protoc binary into the build directory and marks it executable with File.setExecutable(true). This CodeGenException is thrown when the OS refuses to set the execute bit — common on filesystems that do not support permissions.

Source

Thrown at extensions/grpc/codegen/src/main/java/io/quarkus/grpc/codegen/GrpcCodeGen.java:522

            Path artifactPath) throws CodeGenException {
        Path exe = buildDir.resolve(String.format("%s-%s-%s-%s", groupId, artifactId, classifier, packaging));

        if (Files.exists(exe)) {
            return exe;
        }

        if (artifactPath == null) {
            String location = String.format("%s:%s:%s:%s", groupId, artifactId, classifier, packaging);
            throw new CodeGenException("Failed to find " + location + " among dependencies");
        }

        try {
            Files.copy(artifactPath, exe, StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException e) {
            throw new CodeGenException("Failed to copy file: " + artifactPath + " to " + exe, e);
        }
        if (!exe.toFile().setExecutable(true)) {
            throw new CodeGenException("Failed to make the file executable: " + exe);
        }
        return exe;
    }

    private static Path findArtifactPath(ApplicationModel model, String groupId, String artifactId, String classifier,
            String packaging) {
        Path artifactPath = null;

        for (ResolvedDependency artifact : model.getDependencies()) {
            if (groupId.equals(artifact.getGroupId())
                    && artifactId.equals(artifact.getArtifactId())
                    && classifier.equals(artifact.getClassifier())
                    && packaging.equals(artifact.getType())) {
                artifactPath = artifact.getResolvedPaths().getSinglePath();
            }
        }
        return artifactPath;
    }

View on GitHub (pinned to e1c734241f)

Solutions

  1. Move the project/build directory onto a native filesystem (e.g. inside WSL use ~/project, not /mnt/c)
  2. Remount the volume without noexec (mount -o remount,exec) or remove noexec from fstab/docker volume options
  3. Use a POSIX-compliant filesystem for the build (ext4/overlayfs in containers, not NTFS/FAT mounts)
  4. Alternatively supply a working protoc via -Dquarkus.grpc.protoc-path pointing to an already-executable binary

Example fix

# before (WSL)
cd /mnt/c/Users/me/project && mvn compile
# after
cd ~/project && mvn compile
Defensive patterns

Strategy: validation

Validate before calling

Path probe = buildDir.resolve(".exec-probe");
Files.writeString(probe, "#");
if (!probe.toFile().setExecutable(true)) {
    throw new IllegalStateException("Filesystem " + buildDir + " does not support execute bits; move build off noexec/NTFS mounts");
}
Files.deleteIfExists(probe);

Try / catch

try {
    build.run();
} catch (CodeGenException e) {
    if (e.getMessage().contains("Failed to make the file executable")) {
        throw new IllegalStateException("Re-run on an exec-capable filesystem (not noexec/NFS/NTFS)", e);
    }
}

Prevention

When it happens

Trigger: Code generation where the copied protoc/protoc-gen-grpc-java file lives on a filesystem without POSIX exec permissions (NTFS/FAT mounts, Windows drives mounted on Linux, some NFS/SMB shares, WSL /mnt/c), so setExecutable returns false.

Common situations: WSL2 builds writing to /mnt/c instead of the Linux filesystem; CI runners with tmpfs/noexec mounts; Docker volumes mounted with noexec; FAT32 USB drives used as workspace.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05). Data as JSON: /api/errors/42987d612bc0f7a1. Report an issue: GitHub.