nostra13/Android-Universal-Image-Loader · error · IOException
not a readable directory: {dir}
Error message
not a readable directory: {dir} What it means
Thrown by Util.deleteContents (a helper ported from OkHttp's DiskLruCache) when File.listFiles() returns null, meaning the path is not a directory or the process lacks read permission on it. In this library it is called from DiskLruCache/DiskLruCacheUtil when the LruDiskCache initializes and clears its cache directory before use. The IOException propagates up through LruDiskCache construction, aborting disk cache creation.
Source
Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/Util.java:54
char[] buffer = new char[1024];
int count;
while ((count = reader.read(buffer)) != -1) {
writer.write(buffer, 0, count);
}
return writer.toString();
} finally {
reader.close();
}
}
/**
* Deletes the contents of {@code dir}. Throws an IOException if any file
* could not be deleted, or if {@code dir} is not a readable directory.
*/
static void deleteContents(File dir) throws IOException {
File[] files = dir.listFiles();
if (files == null) {
throw new IOException("not a readable directory: " + dir);
}
for (File file : files) {
if (file.isDirectory()) {
deleteContents(file);
}
if (!file.delete()) {
throw new IOException("failed to delete file: " + file);
}
}
}
static void closeQuietly(/*Auto*/Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {View on GitHub (pinned to ba33ec64d0)
Solutions
- Verify the cache path with context.getCacheDir() (always app-writable) instead of external storage
- Ensure the File passed to diskCacheFileNameGenerator/diskCacheFile(...) is created as a directory (mkdirs()) before building the configuration
- Add WRITE_EXTERNAL_STORAGE permission if caching on external storage pre-API 19
- Wrap ImageLoader.getInstance().init(...) in try/catch (IOException/IllegalStateException) and fall back to a noDiskCache configuration if cache setup fails
Example fix
// before
File cacheDir = new File(context.getCacheDir(), "ui/images");
// ... later, without ever creating it:
config.diskCache(new LruDiskCache(cacheDir, ...)); // may throw: not a readable directory
// after
File cacheDir = new File(context.getCacheDir(), "ui/images");
if (!cacheDir.exists() && !cacheDir.mkdirs()) {
cacheDir = context.getCacheDir(); // safe fallback
}
config.diskCache(new LruDiskCache(cacheDir, BaseMd5FileNameGenerator.INSTANCE, 50 * 1024 * 1024, 0)); Defensive patterns
Strategy: validation
Validate before calling
File cacheDir = new File(context.getCacheDir(), "uil");
boolean usable = cacheDir.isDirectory() || cacheDir.mkdirs();
if (usable) {
File[] probe = cacheDir.listFiles();
usable = probe != null; // listFiles() null == not readable
}
if (usable) config.diskCache(new LruDiskCache(cacheDir, BaseMd5FileNameGenerator.INSTANCE, CACHE_SIZE, 0));
// else: omit disk cache from configuration Try / catch
try {
ImageLoader.getInstance().init(configWithDiskCache);
} catch (IOException e) {
// fall back to memory-cache-only config
ImageLoader.getInstance().init(memoryOnlyConfig);
} Prevention
- Always derive cache dirs from context.getCacheDir() so read/write permission is guaranteed
- Create the directory with mkdirs() and verify isDirectory() before passing it to disk cache setup
- Never share one cache directory between processes
When it happens
Trigger: Configuring ImageLoaderConfiguration with diskCache(...) (LruDiskCache/DiskLruCache) where the supplied cache File points to a regular file instead of a directory, a directory with no read permission (chmod 000, restrictive SELinux), or a path that was deleted concurrently between the existence check and listFiles().
Common situations: Passing getCacheDir()+"/subdir" as a String instead of creating the directory first; a previous run crashed mid-directory creation; device storage mounted read-only; on some devices /sdcard access without WRITE_EXTERNAL_STORAGE permission; multi-process apps where another process deleted the cache dir.
Related errors
AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14).
Data as JSON: /api/errors/3928d8cbc7aa93d6.
Report an issue: GitHub.