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

failed to delete file: {file}

Error message

failed to delete file: {file}

What it means

Thrown by Util.deleteContents when File.delete() returns false for an entry inside the cache directory while the LruDiskCache (DiskLruCache) is clearing its directory during initialization or maintenance. It means the OS refused the delete: the file is locked by another process/handle, the directory entry is read-only, or the filesystem is in a bad state. Because deleteContents recurses depth-first, the offending nested File is included in the message.

Source

Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/Util.java:61

			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

  1. Use a private, per-process cache directory (context.getCacheDir() based) so nothing else holds handles to files in it
  2. Ensure only one ImageLoader instance/process owns the disk cache directory
  3. Free storage / remount the volume writable, then restart the app
  4. Catch IOException around ImageLoader init and continue with memory-cache-only configuration

Example fix

// before
ImageLoader.getInstance().init(config); // crashes stack with failed to delete file: ...

// after
try {
    ImageLoader.getInstance().init(config);
} catch (IOException e) {
    L.e("disk cache unusable, falling back", e);
    ImageLoader.getInstance().init(new ImageLoaderConfiguration.Builder(context)
            .memoryCacheSizePercentage(25)
            .build()); // no disk cache
}
Defensive patterns

Strategy: fallback

Validate before calling

boolean canWrite = cacheDir.canWrite();
// best-effort probe: try deleting a temp file
File probe = new File(cacheDir, ".probe");
try {
    if (probe.createNewFile() && probe.delete()) canWrite = true; else canWrite = false;
} catch (IOException e) { canWrite = false; }

Try / catch

try {
    ImageLoader.getInstance().init(config);
} catch (IOException e) {
    L.e("disk cache init failed: " + e.getMessage(), e);
    ImageLoader.getInstance().init(memoryOnlyConfig);
}

Prevention

When it happens

Trigger: DiskLruCache initialization calling deleteContents(directory) on a cache dir containing undeletable entries: a file currently open by another thread/process, read-only media, or a file created by a different app uid in a shared cache path.

Common situations: Two app processes sharing one external-storage cache directory; a crash left a partially-written journal and a stale file handle; SD card mounted read-only or full; OEM storage quirks; antivirus/adb pulling files out of the cache dir while the app starts.

Related errors


AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14). Data as JSON: /api/errors/07a1cb641f4cd855. Report an issue: GitHub.