{"record":{"id":"dd3cb44b9e9d1a0d","repo":"iBotPeaches/Apktool","slug":"destination-directory-path-already-exist","errorCode":null,"errorMessage":"Destination directory (\" + path + \") already exists. Use -f option if you want to overwrite it.","messagePattern":"Destination directory \\(\" \\+ path \\+ \"\\) already exists\\. Use -f option if you want to overwrite it\\.","errorType":"exception","errorClass":"OutDirExistsException","httpStatus":null,"severity":"error","filePath":"brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java","lineNumber":71,"sourceCode":"    private SmaliDecoder mSmaliDecoder;\n    private ResDecoder mResDecoder;\n    private BackgroundWorker mWorker;\n\n    public ApkDecoder(File apkFile, Config config) {\n        mApkFile = new ExtFile(apkFile);\n        mConfig = config;\n        mFirstError = new AtomicReference<>();\n    }\n\n    public void decode(File outDir) throws AndrolibException {\n        if (!mApkFile.isFile() || !mApkFile.canRead()) {\n            throw new InFileNotFoundException(mApkFile.getPath());\n        }\n        // We don't follow symlinks here for safety reasons.\n        if (Files.exists(outDir.toPath(), LinkOption.NOFOLLOW_LINKS)) {\n            if (Files.isDirectory(outDir.toPath(), LinkOption.NOFOLLOW_LINKS)) {\n                if (!mConfig.isForced() && BrutIO.isNonEmptyDirectory(outDir)) {\n                    throw new OutDirExistsException(outDir.getPath());\n                }\n                OS.rmdir(outDir);\n            } else {\n                if (!mConfig.isForced()) {\n                    throw new OutDirExistsException(outDir.getPath());\n                }\n                OS.rmfile(outDir);\n            }\n        }\n        OS.mkdir(outDir);\n\n        if (mConfig.getJobs() > 1) {\n            mWorker = new BackgroundWorker(mConfig.getJobs() - 1);\n        }\n        try {\n            mApkInfo = new ApkInfo();\n            mApkInfo.setVersion(mConfig.getVersion());\n            mApkInfo.setApkFile(mApkFile);","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/iBotPeaches/Apktool/blob/79b63384d7d7e22917e6ea8b453272da7012515b/brut.apktool/apktool-lib/src/main/java/brut/androlib/ApkDecoder.java#L53-L89","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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>."],"exampleFix":"# before\napktool d app.apk\n# after\napktool d -f app.apk -o app_out","handlingStrategy":"validation","validationCode":"if (outDir.exists() && outDir.isDirectory() && BrutIO.isNonEmptyDirectory(outDir)\n        && !config.isForced()) {\n    org.apache.commons.io.FileUtils.deleteQuietly(outDir); // or set forced\n}","typeGuard":null,"tryCatchPattern":"catch (OutDirExistsException e) { config.setForced(true); /* retry decode once */ }","preventionTips":["Always pass -f in scripted/CI decode runs.","Use a unique output dir per run (timestamp/id suffix)."],"tags":["apktool","file-io","decode","overwrite"],"backgroundTag":null,"analyzedSha":"79b63384d7d7e22917e6ea8b453272da7012515b","analyzedAt":"2026-08-14T10:43:28.812Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}