asLody/VirtualApp · error · IOException
Couldn't create directory
Error message
Couldn't create directory
What it means
AtomicFile.startWrite opens the base file for writing; on FileNotFoundException it attempts parent.mkdir() to recreate a missing directory. If that mkdir fails it throws this IOException including the file path. It protects atomic-write users from silently writing into a nonexistent directory.
Solutions
- Ensure the parent directory exists before creating AtomicFile, using mkdirs() on the full chain and checking writable state
- Verify storage is mounted (Environment.getExternalStorageState) and path is app-writable
- Log/inspect the exact path; fix the path construction to live under context.getFilesDir()/getCacheDir()
Example fix
// before
AtomicFile af = new AtomicFile(new File("/data/system/users/0/x.xml"));
// after
File dir = new File("/data/system/users/0");
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException("cannot create " + dir);
}
AtomicFile af = new AtomicFile(new File(dir, "x.xml")); Defensive patterns
Strategy: validation
Validate before calling
File base = new File(dir, "file.xml");
File parent = base.getParentFile();
if (!parent.isDirectory() && !parent.mkdirs()) {
throw new IOException("cannot create " + parent);
}
if (!parent.canWrite()) throw new IOException("not writable: " + parent); Try / catch
try {
FileOutputStream out = atomicFile.startWrite();
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Couldn't create directory")) {
// recreate directory chain or switch to a writable location
}
} Prevention
- Create parent directories with mkdirs() before constructing AtomicFile
- Verify storage mounted and writable (Environment.getExternalStorageState)
- Base file paths under context.getFilesDir()/getCacheDir()
When it happens
Trigger: Calling AtomicFile.startWrite (directly or via writeUserLocked/writeUserListLocked) when the base file's parent directory does not exist and mkdir() returns false (permission denied, parent-of-parent missing, or storage unmounted).
Common situations: External storage unmounted or read-only; data directory wiped while service still holds an AtomicFile; wrong base path constructed for a restricted user; Android scoped-storage restrictions.
Understand the failure class
Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.
Related errors
- Couldn't create
- Couldn't append
- Unable to create application
- Unable to start receiver
- VirtualCore.startup() must called in main thread.
AI-assisted analysis of asLody/VirtualApp@666fefcb5d (2026-09-09).
Data as JSON: /api/errors/231aa95bd14dc2f7.
Report an issue: GitHub.
Appendix: source
Thrown at VirtualApp/lib/src/main/java/com/lody/virtual/helper/utils/AtomicFile.java:88
public FileOutputStream startWrite() throws IOException {
// Rename the current file so it may be used as a backup during the next read
if (mBaseName.exists()) {
if (!mBackupName.exists()) {
if (!mBaseName.renameTo(mBackupName)) {
Log.w("AtomicFile", "Couldn't rename file " + mBaseName
+ " to backup file " + mBackupName);
}
} else {
mBaseName.delete();
}
}
FileOutputStream str = null;
try {
str = new FileOutputStream(mBaseName);
} catch (FileNotFoundException e) {
File parent = mBaseName.getParentFile();
if (!parent.mkdir()) {
throw new IOException("Couldn't create directory " + mBaseName);
}
try {
str = new FileOutputStream(mBaseName);
} catch (FileNotFoundException e2) {
throw new IOException("Couldn't create " + mBaseName);
}
}
return str;
}
/**
* Call when you have successfully finished writing to the stream
* returned by {@link #startWrite()}. This will close, sync, and
* commit the new data. The next attempt to read the atomic file
* will return the new file stream.
*/
public void finishWrite(FileOutputStream str) {
if (str != null) {View on GitHub (pinned to 666fefcb5d)