iBotPeaches/Apktool · error · BrutException

Could not move file:

Error message

Could not move file: 

What it means

Thrown by OS.mvfile when java.nio.Files.move(src, dest, REPLACE_EXISTING) throws IOException. Files.move fails when the source does not exist, the destination's parent directory does not exist, the destination is a non-empty directory, a file is locked (Windows), or an atomic move is required across filesystems (this call is non-atomic but can still fail across stores on some platforms). The BrutException message includes the source path; the original IOException is attached as the cause.

Source

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

        for (File file : files) {
            if (file.isDirectory()) {
                rmdir(file);
            } else {
                rmfile(file);
            }
        }
        rmfile(dir);
    }

    public static void mvfile(String src, String dest) throws BrutException {
        mvfile(new File(src), new File(dest));
    }

    public static void mvfile(File src, File dest) throws BrutException {
        try {
            Files.move(src.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException ex) {
            throw new BrutException("Could not move file: " + src, ex);
        }
    }

    public static void cpfile(String src, String dest) throws BrutException {
        cpfile(new File(src), new File(dest));
    }

    public static void cpfile(File src, File dest) throws BrutException {
        if (!src.isFile()) {
            return;
        }

        try {
            Files.copy(src.toPath(), dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
        } catch (IOException ex) {
            throw new BrutException("Could not copy file: " + src, ex);
        }
    }

View on GitHub (pinned to 79b63384d7)

Solutions

  1. Create the destination parent first: dest.getParentFile() != null && (dest.getParentFile().exists() || dest.getParentFile().mkdirs())
  2. Check src.isFile() before calling, or treat a missing source as a no-op if the move is idempotent in your flow
  3. For cross-filesystem moves, fall back to copy-then-delete: Files.copy then Files.delete (or OS.cpfile + delete) when Files.move throws
  4. Inspect the wrapped cause (ex.getCause()) to distinguish permission/lock failures from missing-path failures

Example fix

// before
OS.mvfile(src, dest); // fails when dest's parent is missing

// after
File parent = dest.getParentFile();
if (parent != null && !parent.exists() && !parent.mkdirs()) {
    throw new BrutException("Cannot create dir: " + parent);
}
OS.mvfile(src, dest);
Defensive patterns

Strategy: validation

Validate before calling

boolean canMove(File src, File dest) {
    if (!src.isFile()) return false;
    File parent = dest.getParentFile();
    return parent != null && (parent.exists() || parent.mkdirs()) && parent.canWrite();
}
// if (canMove(src, dest)) OS.mvfile(src, dest); else handle();

Try / catch

try {
    OS.mvfile(src, dest);
} catch (BrutException e) {
    IOException cause = (IOException) e.getCause();
    if (cause != null && cause.getMessage() != null && cause.getMessage().contains("cross")) {
        OS.cpfile(src, dest); new File(src).delete(); // copy+delete fallback for cross-FS
    } else throw e;
}

Prevention

When it happens

Trigger: OS.mvfile(src, dest) where src is missing, dest.getParentFile() does not exist or is not writable, dest is an open/locked file (Windows), or src and dest live on different mounts/filesystems.

Common situations: Renaming decoded apk artifacts into a build output directory that was never mkdir'd; moving files across partitions (tmpfs to disk); antivirus or another process holding the destination on Windows; races where the source was already moved/consumed; two threads moving the same file.

Related errors


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