MuntashirAkon/AppManager · error · IOException

Destination is a mount point.

Error message

Destination is a mount point.

What it means

Thrown by PathImpl.checkVfs when a copy/move destination resolves to an active VirtualFileSystem mount point in this library. Mount points are special nodes backed by a mounted filesystem (APK/DEX), so writing through them would corrupt or shadow the mount. The operation is aborted with a plain IOException.

Solutions

  1. Choose a destination path that is not a mount point (write next to it, not onto it).
  2. Unmount the filesystem at the destination first with VirtualFileSystem.unmount(mountPoint) (or its Uri-based API), then retry the operation.
  3. If replacing a mount is intended, use the remount option/flag instead of a plain mount/copy.
  4. Before the operation, check VirtualFileSystem.getFileSystem(destUri) != null and route accordingly.

Example fix

// before
newPath.copy(destinationMountPoint, StandardCopyOption.REPLACE_EXISTING);
// after
if (VirtualFileSystem.getFileSystem(destinationMountPoint.getUri()) != null) {
    VirtualFileSystem.unmount(destinationMountPoint.getUri());
}
newPath.copy(destinationMountPoint, StandardCopyOption.REPLACE_EXISTING);
Defensive patterns

Strategy: validation

Validate before calling

if (VirtualFileSystem.getFileSystem(destUri) != null) {
    throw new IllegalArgumentException("Destination is a mount point: " + destUri);
}

Try / catch

try {
    src.copy(dest);
} catch (IOException e) {
    if ("Destination is a mount point.".equals(e.getMessage())) {
        VirtualFileSystem.unmount(dest.getUri());
        src.copy(dest);
    } else throw e;
}

Prevention

When it happens

Trigger: Calling Path copy/move (or any PathImpl API that calls checkVfs) with a destination Uri for which VirtualFileSystem.getFileSystem(uri) != null, i.e. the Uri is currently registered as a mount point; performing the operation without unmounting first.

Common situations: Users of IO/PathUtils try to extract or overwrite files directly onto a mounted APK/DEX mount point (e.g. copying a file onto /mnt/apk/... style path); remount flows that forgot the remount flag; stale mounts left over from a previous session.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/615288b6cdf69467. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/io/github/muntashirakon/io/PathImpl.java:1381

        return documentFile;
    }

    @Nullable
    private static DocumentFile resolveFileOrNull(@NonNull DocumentFile documentFile) {
        DocumentFile realDocumentFile = getRealDocumentFile(documentFile);
        if (!realDocumentFile.isDirectory()) {
            return realDocumentFile;
        }
        // Try original
        if (!documentFile.isDirectory()) {
            return documentFile;
        }
        return null;
    }

    private static void checkVfs(Uri uri) throws IOException {
        if (VirtualFileSystem.getFileSystem(uri) != null) {
            throw new IOException("Destination is a mount point.");
        }
    }

    private static boolean isDocumentsProvider(@NonNull Context context, @Nullable String authority) {
        final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
        final List<ResolveInfo> infos = context.getPackageManager().queryIntentContentProviders(intent, 0);
        for (ResolveInfo info : infos) {
            if (Objects.equals(authority, info.providerInfo.authority)) {
                return true;
            }
        }
        return false;
    }

    private static class ProxyStorageCallback extends StorageManagerCompat.ProxyFileDescriptorCallbackCompat {
        @NonNull
        private final FileChannel mChannel;

View on GitHub (pinned to 0152f468fc)