iBotPeaches/Apktool · error · BrutException

Execution failed (exit code =

Error message

Execution failed (exit code = 

What it means

Thrown by OS.exec after an external process started successfully but returned a non-zero exit code. The message includes the numeric exit code and the full command array. This means the binary was found and ran — it failed on its own (bad arguments, missing input files, version mismatch). The child's stderr was forwarded to the parent's stderr by StreamForwarder, so the underlying tool's message usually appears in the log just before this exception.

Source

Thrown at brut.j.util/src/main/java/brut/util/OS.java:147

            if (file.isDirectory()) {
                cpdir(file, destFile);
            } else {
                cpfile(file, destFile);
            }
        }
    }

    public static void exec(String[] cmd) throws BrutException {
        try {
            ProcessBuilder builder = new ProcessBuilder(cmd);
            Process ps = builder.start();

            new StreamForwarder(ps.getErrorStream(), "ERROR").start();
            new StreamForwarder(ps.getInputStream(), "OUTPUT").start();

            int exitValue = ps.waitFor();
            if (exitValue != 0) {
                throw new BrutException("Execution failed (exit code = " + exitValue + "): " + Arrays.toString(cmd));
            }
        } catch (IOException ex) {
            throw new BrutException("could not exec: " + Arrays.toString(cmd), ex);
        } catch (InterruptedException ex) {
            throw new BrutException("could not exec : " + Arrays.toString(cmd), ex);
        }
    }

    public static String execAndReturn(String[] cmd) {
        ExecutorService executor = Executors.newCachedThreadPool();
        try {
            ProcessBuilder builder = new ProcessBuilder(cmd);
            builder.redirectErrorStream(true);

            Process process = builder.start();
            StreamCollector collector = new StreamCollector(process.getInputStream());
            executor.execute(collector);
            process.waitFor(15, TimeUnit.SECONDS);

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Re-run with the child's stderr visible — StreamForwarder already pipes it to your stderr — and fix the argument or input the child complains about
  2. Verify the exact binary being invoked (which aapt / version flag) matches what your inputs require; upgrade apktool or the bundled tool
  3. Validate input files exist and are readable before invoking the external command
  4. For CI failures, check the child's exit-code contract (e.g. 127 = command not found, 139 = segfault) to narrow env vs. args

Example fix

// before
OS.exec(new String[]{aapt, "p", "-f", "-M", manifest, "-F", out}); // exit 1

// after
if (!new File(manifest).isFile()) throw new BrutException("missing manifest: " + manifest);
OS.exec(new String[]{aapt, "p", "-f", "-M", manifest, "-F", out});
// on failure: child stderr is already forwarded — read it for the real cause
Defensive patterns

Strategy: try-catch

Validate before calling

boolean inputsReady(String[] cmd, int firstInputArgIdx) {
    for (int i = firstInputArgIdx; i < cmd.length; i++) {
        File f = new File(cmd[i]);
        if (f.getPath().startsWith("-") || i < firstInputArgIdx) continue;
        if (f.exists() && !f.canRead()) return false;
    }
    return new File(cmd[0]).canExecute() || Boolean.TRUE;
}

Try / catch

try {
    OS.exec(cmd);
} catch (BrutException e) {
    String m = e.getMessage();
    if (m.startsWith("Execution failed")) {
        // child ran and failed: its stderr was forwarded to our stderr — mine it for the cause
        throw new BuildFailure("tool exited non-zero: " + m, e);
    }
    throw e;
}

Prevention

When it happens

Trigger: OS.exec(new String[]{...}) where the spawned tool (e.g. aapt, apkbuilder, zip, keytool) exits non-zero: invalid flags, missing/locked input file, unsupported format, out-of-memory in the child, or a different tool version with changed CLI syntax.

Common situations: aapt rejecting a newer Android resource format than the bundled aapt supports; incompatible platform-tools or JDK version bundled with the library; passing Windows-style paths on Unix; child printing 'file not found' for an input apk; CI environments missing 32-bit binaries or libz.

Related errors


AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14). Data as JSON: /api/errors/5d89fbf36b53494c. Report an issue: GitHub.