elastic/elasticsearch · error · GradleException

Failed to read exec output

Error message

Failed to read exec output

What it means

LoggedExec.run() wraps any exception thrown while logging the output of a failed process (non-zero exit, logger not at info). After detecting exitValue != 0, it calls outputLogger.accept(getLogger()) which invokes byteStreamToString(out) — a cast of OutputStream to ByteArrayOutputStream. If that cast or string conversion fails, the original failure is masked and rethrown as this GradleException.

Solutions

  1. Inspect the wrapped cause (GradleException.getCause()) for the real failure — typically a ClassCastException from byteStreamToString.
  2. If subclassing LoggedExec, ensure the `out` OutputStream passed to the logging path remains a ByteArrayOutputStream.
  3. Run with --info to take the early-return branch that bypasses this output-logging code entirely.
Defensive patterns

Strategy: try-catch

Try / catch

try { loggedExec.getActions(); } catch (GradleException e) { if (e.getMessage().contains("Failed to read exec output")) { log.error("Underlying cause:", e.getCause()); } throw e; }

Prevention

When it happens

Trigger: An executed process returns non-zero, logging level is above info (so the output-logging branch runs), and the output-logging lambda throws — typically because `out` is not a ByteArrayOutputStream (e.g., a custom OutputStream was injected) or a charset/IO issue occurs during toString.

Common situations: Subclassing LoggedExec and overriding the OutputStream handling; corruption of the captured stream; edge cases where the ByteArrayOutputStream cast in byteStreamToString fails. Rare in practice — usually indicates a subclassing bug.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/9f2f6fe6ffc9bdc2. Report an issue: GitHub.

Appendix: source

Thrown at build-tools/src/main/java/org/elasticsearch/gradle/LoggedExec.java:184

            }
            if (getStandardInput().isPresent()) {
                execSpec.setStandardInput(new ByteArrayInputStream(getStandardInput().get().getBytes(StandardCharsets.UTF_8)));
            }
        });
        int exitValue = execResult.getExitValue();

        if (exitValue == 0 && getCaptureOutput().get()) {
            output = byteStreamToString(out);
        }
        if (getLogger().isInfoEnabled() == false) {
            if (exitValue != 0) {
                try {
                    if (getIndentingConsoleOutput().isPresent() == false) {
                        getLogger().error("Output for " + getExecutable().get() + ":");
                    }
                    outputLogger.accept(getLogger());
                } catch (Exception e) {
                    throw new GradleException("Failed to read exec output", e);
                }
                throw new GradleException(
                    String.format("Process '%s %s' finished with non-zero exit value %d", getExecutable().get(), getArgs().get(), exitValue)
                );
            }
        }

    }

    private String byteStreamToString(OutputStream out) {
        return ((ByteArrayOutputStream) out).toString(StandardCharsets.UTF_8);
    }

    public static ExecResult exec(ExecOperations execOperations, Action<ExecSpec> action) {
        return genericExec(execOperations::exec, action);
    }

    public static ExecResult javaexec(ExecOperations project, Action<JavaExecSpec> action) {

View on GitHub (pinned to db6a809a66)