quarkusio/quarkus · error · CodeGenFailureException

failed to set file: ${script} executable. Protoc invocation

Error message

failed to set file: ${script} executable. Protoc invocation may fail

What it means

After writing the quarkus-grpc wrapper script, writeScript calls File.setExecutable(true); if the OS cannot set the execute bit it throws GrpcCodeGenFailureException with this message, warning that the subsequent protoc invocation will likely fail. Note it is a GrpcCodeGenFailureException, not CodeGenException.

Source

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

            return writeScript(buildDir, pluginPath, "#!/bin/sh\n", ".sh");
        } else {
            return writeScript(buildDir, pluginPath, "@echo off\r\n", ".cmd");
        }
    }

    private static Path writeScript(Path buildDir, Path pluginPath, String shebang, String suffix) throws CodeGenException {
        Path script;
        try {
            script = Files.createTempFile(buildDir, "quarkus-grpc", suffix);
            try (BufferedWriter writer = Files.newBufferedWriter(script)) {
                writer.write(shebang);
                writePluginExeCmd(pluginPath, writer);
            }
        } catch (IOException e) {
            throw new CodeGenException("Failed to create a wrapper script for quarkus-grpc plugin", e);
        }
        if (!script.toFile().setExecutable(true)) {
            throw new CodeGenFailureException("failed to set file: " + script + " executable. Protoc invocation may fail");
        }
        return script;
    }

    private static void writePluginExeCmd(Path pluginPath, BufferedWriter writer) throws IOException {
        writer.write("\"" + io.smallrye.common.process.ProcessUtil.pathOfJava().toString() + "\" -cp \"" +
                pluginPath.toAbsolutePath() + "\" " + quarkusProtocPluginMain);
        writer.newLine();
    }

    private static boolean containsQuarkusKotlin(Collection<ResolvedDependency> dependencies) {
        return dependencies.stream().anyMatch(new Predicate<ResolvedDependency>() {
            @Override
            public boolean test(ResolvedDependency rd) {
                return rd.getGroupId().equalsIgnoreCase("io.quarkus")
                        && rd.getArtifactId().equalsIgnoreCase("quarkus-kotlin");
            }
        });

View on GitHub (pinned to e1c734241f)

Solutions

  1. Move the build to a filesystem supporting execute bits (Linux ext4/overlayfs, WSL native home dir instead of /mnt/c)
  2. Remount the volume without noexec (mount -o remount,exec or drop noexec from fstab/docker volume options)
  3. Run the build inside a container with exec permissions on the workspace mount
  4. If on Windows, confirm the failure is benign for .cmd files — but prefer building in a Linux container to avoid it

Example fix

# before
docker run -v $(pwd):/project:noexec quarkus-build
# after
docker run -v $(pwd):/project quarkus-build
Defensive patterns

Strategy: validation

Validate before calling

// probe exec-bit support in the build directory before codegen
Path probe = buildDir.resolve(".exec-probe.sh");
Files.writeString(probe, "#!/bin/sh\n");
if (!probe.toFile().setExecutable(true)) {
    throw new IllegalStateException("Cannot set exec bit on " + buildDir + " — noexec mount? Move the build directory.");
}
Files.deleteIfExists(probe);

Try / catch

try {
    build.run();
} catch (GrpcCodeGenFailureException e) {
    if (e.getMessage().contains("failed to set file")) {
        throw new IllegalStateException("Build dir lacks exec permission support; remount without noexec or move workspace", e);
    }
}

Prevention

When it happens

Trigger: Code generation where the newly created .sh/.cmd wrapper script lives on a filesystem that rejects execute permissions — noexec mounts, NTFS/FAT via WSL /mnt/c, NFS/SMB shares, Windows FAT-formatted drives.

Common situations: noexec Docker volume mounts for the build directory; WSL working on /mnt/c; network home directories (NFS with root_squash/noexec); CI tmpfs with noexec.

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/56acee57c43bfa00. Report an issue: GitHub.