MuntashirAkon/AppManager · error · IOException

exists and it is not a directory.

Error message

 exists and it is not a directory.

What it means

Thrown by PathImpl's mkdirs helper when an intermediate path segment already exists but is a regular file rather than a directory. While creating the directory chain, the library finds an existing document with the segment's name whose isDirectory() is false and aborts rather than overwrite.

Source

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

            return null;
        }
        // FIXME: 9/9/23 This doesn't actually work for content URIs
        Uri parentUri = Paths.removeLastPathSegment(mountPoint);
        return new PathImpl(context, parentUri).documentFile;
    }

    @NonNull
    private static DocumentFile createArbitraryDirectories(@NonNull DocumentFile documentFile,
                                                           @NonNull String[] names,
                                                           int length) throws IOException {
        DocumentFile file = getRealDocumentFile(documentFile);
        for (int i = 0; i < length; ++i) {
            Path fsRoot = VirtualFileSystem.getFsRoot(Paths.appendPathSegment(file.getUri(), names[i]));
            DocumentFile t = fsRoot != null ? fsRoot.documentFile : file.findFile(names[i]);
            if (t == null) {
                t = file.createDirectory(names[i]);
            } else if (!t.isDirectory()) {
                throw new IOException(t.getUri() + " exists and it is not a directory.");
            }
            if (t == null) {
                throw new IOException("Could not create directory " + file.getUri() + File.separatorChar + names[i]);
            }
            file = t;
        }
        return file;
    }

    @NonNull
    private static DocumentFile getRealDocumentFile(@NonNull DocumentFile documentFile) {
        Path fsRoot = VirtualFileSystem.getFsRoot(documentFile.getUri());
        if (fsRoot != null) {
            return fsRoot.documentFile;
        }
        return documentFile;
    }

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Inspect the existing document at the colliding segment and rename/delete it if appropriate
  2. Use a different base directory for the new tree
  3. Check each segment with findFile() + isDirectory() before creating to give a precise error

Example fix

// before
dir.createDirectories("logs/session/x");
// after
Path p = dir;
for (String seg : new String[]{"logs", "session", "x"}) {
    Path child = p.findFile(seg);
    if (child != null && !child.isDirectory()) {
        throw new FileAlreadyExistsException("File blocks directory creation: " + child);
    }
    p = (child != null) ? child : p.createDirectory(seg);
}
Defensive patterns

Strategy: validation

Validate before calling

for (String seg : segments) { Path c = base.findFile(seg); if (c != null && !c.isDirectory()) throw new FileAlreadyExistsException(seg); }

Type guard

null

Try / catch

try { dir.createDirectories(chain); } catch (IOException e) { logCollision(chain); throw e; }

Prevention

When it happens

Trigger: Calling Path.createDirectories()/createDirectoryAndParents-style APIs where a component of the path (e.g. 'a/b/c' with 'a/b' being an existing file) collides with an existing non-directory document.

Common situations: Path layout changed between app versions (old file now sits where a folder is expected); data restored from backup creating files where directories should be; typos causing name collisions with existing files.

Related errors


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