MuntashirAkon/AppManager · error · IOException
is a directory
Error message
is a directory
What it means
openOutputStream(append) calls resolveFileOrNull(this.documentFile); when resolution yields null the underlying document is (or resolves to) a directory, and the method throws IOException(uri + " is a directory"). Directories have no byte stream, so opening an output stream on them is meaningless.
Source
Thrown at app/src/main/java/io/github/muntashirakon/io/PathImpl.java:1206
throw (FileNotFoundException) new FileNotFoundException("Could not open file " + file).initCause(e);
}
} // else use the default content provider
} else if (documentFile instanceof VirtualDocumentFile) {
int modeBits = ParcelFileDescriptor.parseMode(mode);
try {
return ((VirtualDocumentFile) documentFile).openFileDescriptor(modeBits);
} catch (IOException e) {
throw (FileNotFoundException) new FileNotFoundException(e.getMessage()).initCause(e);
}
}
return FileUtils.getFdFromUri(context, documentFile.getUri(), mode);
}
@NonNull
public OutputStream openOutputStream(boolean append) throws IOException {
DocumentFile documentFile = resolveFileOrNull(this.documentFile);
if (documentFile == null) {
throw new IOException(this.documentFile.getUri() + " is a directory");
}
if (documentFile instanceof ExtendedRawDocumentFile) {
try {
return Objects.requireNonNull(getFile()).newOutputStream(append);
} catch (IOException e) {
throw new IOException("Could not open file for writing: " + documentFile.getUri(), e);
}
} else if (documentFile instanceof VirtualDocumentFile) {
return ((VirtualDocumentFile) documentFile).openOutputStream(append);
}
String mode = "w" + (append ? "a" : "t");
OutputStream os = context.getContentResolver().openOutputStream(documentFile.getUri(), mode);
if (os == null) {
throw new IOException("Could not resolve Uri: " + documentFile.getUri());
}
return os;
}
View on GitHub (pinned to 0152f468fc)
Solutions
- Check path.isDirectory() before opening a stream
- Call getUri()/lastPathSegment checks or list files and open streams only on files
- Resolve to the intended child file inside the directory first
Example fix
// before
OutputStream os = path.openOutputStream();
// after
if (path.isDirectory()) throw new IllegalArgumentException("Expected a file: " + path.getUri());
OutputStream os = path.openOutputStream(); Defensive patterns
Strategy: validation
Validate before calling
if (path.isDirectory()) {
throw new IllegalArgumentException("Cannot open output stream on a directory");
} Try / catch
try {
OutputStream os = path.openOutputStream(append);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().endsWith(" is a directory")) {
// resolve to the intended child file and retry
} else throw e;
} Prevention
- Always isDirectory()-check before stream APIs
- Filter listFiles() results to files before reading/writing
- Treat SAF tree URIs as directories unless resolved to a document
When it happens
Trigger: Calling path.openOutputStream()/openOutputStream(true) on a Path whose document is a directory (resolveFileOrNull returns null), e.g. a directory URI or a path that got resolved to a directory.
Common situations: Using a user-picked SAF tree/document URI that points at a folder, iterating entries without filtering out directories, or path construction that accidentally selects a directory.
Related errors
- Existing file is not a directory
- Could not create directory named
- Could not open file for writing:
- Could not get backup files.
- Could not retrieve metadata from backup.
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/3d277f8c3726a0ee.
Report an issue: GitHub.