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
- 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
- Verify the exact binary being invoked (which aapt / version flag) matches what your inputs require; upgrade apktool or the bundled tool
- Validate input files exist and are readable before invoking the external command
- 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
- Capture and log the child's stderr (StreamForwarder already prints it) so exit-code failures are diagnosable
- Pin tool versions (aapt, platform-tools) matching your input formats
- Validate input file existence before invoking external tools
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.