nostra13/Android-Universal-Image-Loader · error · IOException

not a readable directory

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.

Solutions

  1. Verify the cache path with context.getCacheDir() (always app-writable) instead of external storage
  2. Ensure the File passed to diskCacheFileNameGenerator/diskCacheFile(...) is created as a directory (mkdirs()) before building the configuration
  3. Add WRITE_EXTERNAL_STORAGE permission if caching on external storage pre-API 19
  4. 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

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.

Appendix: 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)