{"record":{"id":"3928d8cbc7aa93d6","repo":"nostra13/Android-Universal-Image-Loader","slug":"not-a-readable-directory-dir","errorCode":null,"errorMessage":"not a readable directory: {dir}","messagePattern":"not a readable directory: (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/Util.java","lineNumber":54,"sourceCode":"\t\t\tchar[] buffer = new char[1024];\n\t\t\tint count;\n\t\t\twhile ((count = reader.read(buffer)) != -1) {\n\t\t\t\twriter.write(buffer, 0, count);\n\t\t\t}\n\t\t\treturn writer.toString();\n\t\t} finally {\n\t\t\treader.close();\n\t\t}\n\t}\n\n\t/**\n\t * Deletes the contents of {@code dir}. Throws an IOException if any file\n\t * could not be deleted, or if {@code dir} is not a readable directory.\n\t */\n\tstatic void deleteContents(File dir) throws IOException {\n\t\tFile[] files = dir.listFiles();\n\t\tif (files == null) {\n\t\t\tthrow new IOException(\"not a readable directory: \" + dir);\n\t\t}\n\t\tfor (File file : files) {\n\t\t\tif (file.isDirectory()) {\n\t\t\t\tdeleteContents(file);\n\t\t\t}\n\t\t\tif (!file.delete()) {\n\t\t\t\tthrow new IOException(\"failed to delete file: \" + file);\n\t\t\t}\n\t\t}\n\t}\n\n\tstatic void closeQuietly(/*Auto*/Closeable closeable) {\n\t\tif (closeable != null) {\n\t\t\ttry {\n\t\t\t\tcloseable.close();\n\t\t\t} catch (RuntimeException rethrown) {\n\t\t\t\tthrow rethrown;\n\t\t\t} catch (Exception ignored) {","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/nostra13/Android-Universal-Image-Loader/blob/ba33ec64d0daaa881d35852460e78c58d086bc18/library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/Util.java#L36-L72","documentation":"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.","triggerScenarios":"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().","commonSituations":"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.","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"],"exampleFix":"// before\nFile cacheDir = new File(context.getCacheDir(), \"ui/images\");\n// ... later, without ever creating it:\nconfig.diskCache(new LruDiskCache(cacheDir, ...)); // may throw: not a readable directory\n\n// after\nFile cacheDir = new File(context.getCacheDir(), \"ui/images\");\nif (!cacheDir.exists() && !cacheDir.mkdirs()) {\n    cacheDir = context.getCacheDir(); // safe fallback\n}\nconfig.diskCache(new LruDiskCache(cacheDir, BaseMd5FileNameGenerator.INSTANCE, 50 * 1024 * 1024, 0));","handlingStrategy":"validation","validationCode":"File cacheDir = new File(context.getCacheDir(), \"uil\");\nboolean usable = cacheDir.isDirectory() || cacheDir.mkdirs();\nif (usable) {\n    File[] probe = cacheDir.listFiles();\n    usable = probe != null; // listFiles() null == not readable\n}\nif (usable) config.diskCache(new LruDiskCache(cacheDir, BaseMd5FileNameGenerator.INSTANCE, CACHE_SIZE, 0));\n// else: omit disk cache from configuration","typeGuard":null,"tryCatchPattern":"try {\n    ImageLoader.getInstance().init(configWithDiskCache);\n} catch (IOException e) {\n    // fall back to memory-cache-only config\n    ImageLoader.getInstance().init(memoryOnlyConfig);\n}","preventionTips":["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"],"tags":["disk-cache","io","filesystem","permissions","configuration"],"backgroundTag":null,"analyzedSha":"ba33ec64d0daaa881d35852460e78c58d086bc18","analyzedAt":"2026-08-14T15:41:15.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}