nostra13/Android-Universal-Image-Loader · error · IOException
failed to delete {file}
Error message
failed to delete {file} What it means
IOException thrown by DiskLruCache.remove() when a clean file of the entry exists but File.delete() returns false. The cache keeps its size accounting consistent with the filesystem, so a file it cannot delete is treated as a hard failure rather than silently leaking the entry.
Source
Thrown at library/src/main/java/com/nostra13/universalimageloader/cache/disc/impl/ext/DiskLruCache.java:617
/**
* Drops the entry for {@code key} if it exists and can be removed. Entries
* actively being edited cannot be removed.
*
* @return true if an entry was removed.
*/
public synchronized boolean remove(String key) throws IOException {
checkNotClosed();
validateKey(key);
Entry entry = lruEntries.get(key);
if (entry == null || entry.currentEditor != null) {
return false;
}
for (int i = 0; i < valueCount; i++) {
File file = entry.getCleanFile(i);
if (file.exists() && !file.delete()) {
throw new IOException("failed to delete " + file);
}
size -= entry.lengths[i];
fileCount--;
entry.lengths[i] = 0;
}
redundantOpCount++;
journalWriter.append(REMOVE + ' ' + key + '\n');
lruEntries.remove(key);
if (journalRebuildRequired()) {
executorService.submit(cleanupCallable);
}
return true;
}
/** Returns true if this cache has been closed. */View on GitHub (pinned to ba33ec64d0)
Solutions
- Close any open Snapshot streams (snapshot.close()) for the entry before calling remove().
- Verify the cache directory is writable and on healthy storage; prefer context.getCacheDir() (internal) over external storage.
- As a last resort, catch the IOException and wipe/rebuild the whole cache directory, since accounting is now untrustworthy.
Example fix
// before
Snapshot snap = cache.get(key);
InputStream is = snap.getInputStream(0);
// ... use is, never close ...
cache.remove(key); // may fail: file still open
// after
Snapshot snap = cache.get(key);
try (InputStream is = snap.getInputStream(0)) {
// ... use is ...
} finally {
snap.close();
}
cache.remove(key); Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure no open streams on the entry before removal Snapshot snap = cache.get(key); if (snap != null) snap.close(); // releases open InputStreams cache.remove(key);
Try / catch
try {
cache.remove(key);
} catch (IOException deleteFailed) {
// size accounting is now suspect: rebuild the cache wholesale
try { cache.delete(); } catch (IOException wipeFailed) { log(wipeFailed); }
cache = reopenFreshCache(dir);
} Prevention
- Always close Snapshot InputStreams (try-with-resources) before removing entries.
- Keep the cache on internal storage (context.getCacheDir()) where deletion is reliable.
- Monitor free space — a nearly-full or damaged volume is the top cause of failed deletes.
When it happens
Trigger: cache.remove(key) while another process/stream still holds the file open (Windows or a still-open Snapshot InputStream), read-only filesystem or SELinux denial on the cache dir, or the file being deleted concurrently by an external cleanup.
Common situations: Android device with full/damaged emulated storage; a Snapshot's InputStream not closed before remove(); cache directory on external storage unmounted mid-operation; running on a desktop JVM against a locked file.
Related errors
- unexpected journal header: [{magic}, {version}, {valueCountS
- unexpected journal line: {line}
- unexpected journal line: {strings}
- not a readable directory: {dir}
- failed to delete file: {file}
AI-assisted analysis of nostra13/Android-Universal-Image-Loader@ba33ec64d0 (2026-08-14).
Data as JSON: /api/errors/a44b99f3eb4b7fa4.
Report an issue: GitHub.