iBotPeaches/Apktool · error · OutDirExistsException
Destination directory (" + path + ") already exists. Use -f
Error message
Destination directory (" + path + ") already exists. Use -f option if you want to overwrite it. What it means
OutDirExistsException thrown by ApkDecoder.decode() when the output directory exists, is a non-empty directory, and the force/overwrite option (-f / config.isForced()) is not set. Apktool refuses to clobber an existing decode tree to avoid mixing stale files from a previous decode with new output. Note that an existing EMPTY directory is silently removed (OS.rmdir) and recreated.
Source
Thrown at brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java:71
private SmaliDecoder mSmaliDecoder;
private ResDecoder mResDecoder;
private BackgroundWorker mWorker;
public ApkDecoder(File apkFile, Config config) {
mApkFile = new ExtFile(apkFile);
mConfig = config;
mFirstError = new AtomicReference<>();
}
public void decode(File outDir) throws AndrolibException {
if (!mApkFile.isFile() || !mApkFile.canRead()) {
throw new InFileNotFoundException(mApkFile.getPath());
}
// We don't follow symlinks here for safety reasons.
if (Files.exists(outDir.toPath(), LinkOption.NOFOLLOW_LINKS)) {
if (Files.isDirectory(outDir.toPath(), LinkOption.NOFOLLOW_LINKS)) {
if (!mConfig.isForced() && BrutIO.isNonEmptyDirectory(outDir)) {
throw new OutDirExistsException(outDir.getPath());
}
OS.rmdir(outDir);
} else {
if (!mConfig.isForced()) {
throw new OutDirExistsException(outDir.getPath());
}
OS.rmfile(outDir);
}
}
OS.mkdir(outDir);
if (mConfig.getJobs() > 1) {
mWorker = new BackgroundWorker(mConfig.getJobs() - 1);
}
try {
mApkInfo = new ApkInfo();
mApkInfo.setVersion(mConfig.getVersion());
mApkInfo.setApkFile(mApkFile);View on GitHub (pinned to 79b63384d7)
Solutions
- Add the -f flag: `apktool d -f app.apk` (or config.setForced(true)).
- Delete or move the existing output directory before re-running.
- Decode into a fresh directory with -o <newdir>.
Example fix
# before apktool d app.apk # after apktool d -f app.apk -o app_out
Defensive patterns
Strategy: validation
Validate before calling
if (outDir.exists() && outDir.isDirectory() && BrutIO.isNonEmptyDirectory(outDir)
&& !config.isForced()) {
org.apache.commons.io.FileUtils.deleteQuietly(outDir); // or set forced
} Try / catch
catch (OutDirExistsException e) { config.setForced(true); /* retry decode once */ } Prevention
- Always pass -f in scripted/CI decode runs.
- Use a unique output dir per run (timestamp/id suffix).
When it happens
Trigger: Running `apktool d app.apk` twice into the same default directory (app/) without -f; calling decode() programmatically with a Config that has setForced(false) while outDir contains files.
Common situations: Re-decoding after a failed or interrupted run; CI jobs that re-run in an uncleaned workspace; scripted loops that always use the same output directory.
Related errors
- Input file (" + path + ") was not found or was not readable.
- Could not find framework resources for package ID {pkgId}. Y
- Could not generate:
- Could not load resources.arsc from file: {apkFile}
- Framework package not found: id=0x%02x
AI-assisted analysis of iBotPeaches/Apktool@79b63384d7 (2026-08-14).
Data as JSON: /api/errors/dd3cb44b9e9d1a0d.
Report an issue: GitHub.