{"record":{"id":"7c7778cc68c96882","repo":"bumptech/glide","slug":"failed-to-create-cache-directory","errorCode":null,"errorMessage":"Failed to create cache directory: {}","messagePattern":"Failed to create cache directory: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"integration/sqljournaldiskcache/src/main/java/com/bumptech/glide/integration/sqljournaldiskcache/JournaledLruDiskCache.java","lineNumber":130,"sourceCode":"    recoveryManager = new RecoveryManager(this, cacheDirectory, journal, workLooper);\n  }\n\n  private static Looper getBackgroundLooper() {\n    HandlerThread workThread =\n        new HandlerThread(\"disk_cache_journal\", Process.THREAD_PRIORITY_BACKGROUND);\n    workThread.start();\n    return workThread.getLooper();\n  }\n\n  @SuppressWarnings(\"checkstyle:UnnecessaryParentheses\") // Readability\n  private void openIfNotOpen() {\n    if (!isOpen) {\n      synchronized (this) {\n        if (!isOpen) {\n          boolean createdDirectory =\n              cacheDirectory.mkdirs() || (cacheDirectory.exists() && cacheDirectory.isDirectory());\n          if (!createdDirectory) {\n            throw new IllegalStateException(\"Failed to create cache directory: \" + cacheDirectory);\n          }\n          journal.open();\n          isOpen = true;\n          recoveryManager.triggerRecovery();\n        }\n      }\n    }\n  }\n\n  // TODO(judds): rather than polling, we should use Android's FileObserver.\n  private void verifyCanaryOrClear() {\n    if (fileSystem.exists(canaryFile)) {\n      return;\n    }\n\n    synchronized (this) {\n      if (fileSystem.exists(canaryFile)) {\n        return;","sourceCodeStart":112,"sourceCodeEnd":148,"githubUrl":"https://github.com/bumptech/glide/blob/eb14a895d8f866e6a08c3e19d50ea3bd2c12c20a/integration/sqljournaldiskcache/src/main/java/com/bumptech/glide/integration/sqljournaldiskcache/JournaledLruDiskCache.java#L112-L148","documentation":"Thrown by JournaledLruDiskCache.openIfNotOpen() when the cache directory cannot be created or verified. mkdirs() must succeed OR the path must already exist as a directory; if neither holds, the cache cannot be opened.","triggerScenarios":"cacheDirectory.mkdirs() returns false and (cacheDirectory.exists() is false or cacheDirectory.isDirectory() is false). Causes include missing filesystem permissions, a non-directory file occupying the path, or read-only storage.","commonSituations":"App lacks WRITE_EXTERNAL_STORAGE on older Android versions for the chosen path; a file (not directory) exists at the cache path; the path points to private external storage not yet mounted; security/SAF restrictions on scoped storage; parent directory does not exist and mkdirs fails.","solutions":["Use context.getCacheDir() or context.getCodeCacheDir() for app-private reliable storage.","Verify the directory path is writable and that no regular file occupies it.","Request the appropriate storage permission, or migrate to app-specific scoped-storage paths.","Ensure external storage is mounted (Environment.getExternalStorageState()) before using external paths.","Catch the exception and fall back to a different cache location or disable disk caching."],"exampleFix":"// before\nval dir = File(Environment.getExternalStorageDirectory(), \"glide_cache\")\n// may fail: permissions / scoped storage\n\n// after\nval dir = context.cacheDir.resolve(\"glide_cache\") // app-private, always writable","handlingStrategy":"validation","validationCode":"// Validate the cache directory before constructing the cache.\nfun safeCacheDir(context: Context, name: String): File {\n  val dir = File(context.cacheDir, name)\n  if (!dir.exists() && !dir.mkdirs()) {\n    throw IllegalStateException(\"Cannot create cache dir: $dir\")\n  }\n  check(dir.isDirectory) { \"Cache path is not a directory: $dir\" }\n  check(dir.canWrite()) { \"Cache dir not writable: $dir\" }\n  return dir\n}","typeGuard":null,"tryCatchPattern":"try {\n  diskCache.open()\n} catch (e: IllegalStateException) {\n  if (e.message?.contains(\"Failed to create cache directory\") == true) {\n    // fall back to app-private cache dir or disable disk caching\n    useFallbackCacheDir(context)\n  } else throw e\n}","preventionTips":["Prefer context.getCacheDir() for reliable app-private storage.","Verify the path is a writable directory and not occupied by a file.","Handle scoped-storage/permission constraints on the target Android version."],"tags":["sqljournaldiskcache","integration","filesystem","permissions","storage","runtime"],"backgroundTag":null,"analyzedSha":"eb14a895d8f866e6a08c3e19d50ea3bd2c12c20a","analyzedAt":"2026-08-14T01:43:54.821Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}