bumptech/glide · error · IllegalStateException

Failed to delete entry, key: {}, size: {}, actually deleted:

Error message

Failed to delete entry, key: {}, size: {}, actually deleted: {}

What it means

Thrown by Journal during a single-key delete when executeUpdateDelete() does not delete exactly one row. The journal expects the targeted key to resolve to exactly one deletable row; a result other than 1 means the row was absent (or duplicated), breaking the size-accounting invariant.

Source

Thrown at integration/sqljournaldiskcache/src/main/java/com/bumptech/glide/integration/sqljournaldiskcache/Journal.java:307

    SizeSQLiteTransactionListener sizeListener = sizeJournal.prepareSizeTransaction();
    db.beginTransactionWithListenerNonExclusive(sizeListener);
    try {
      // We may be asked to abort a put that failed before the entry was updated, so we will
      // occasionally fail to find the entry here.
      boolean isKeyPresent = 0 != containsKeyStatement.simpleQueryForLong();
      if (!isKeyPresent) {
        return;
      }
      long entrySize;
      try {
        entrySize = selectNotPendingSizeStatement.simpleQueryForLong();
      } catch (SQLiteDoneException e) {
        // No row found for this key that is not pending delete.
        entrySize = 0;
      }
      int deleted = deleteEntryStatement.executeUpdateDelete();
      if (deleted != 1) {
        throw new IllegalStateException(
            "Failed to delete entry"
                + ", key: "
                + key
                + ", size: "
                + entrySize
                + ", actually deleted: "
                + deleted);
      } else {
        // If the item is pending delete its size is 0 here - skip decrementing.
        if (entrySize != 0) {
          sizeJournal.decrementSizeInTransaction(sizeListener, entrySize);
        }
      }
      db.setTransactionSuccessful();
    } finally {
      db.endTransaction();
      statementPool.offer(CONTAINS_KEY_SQL, containsKeyStatement);
      statementPool.offer(SELECT_ENTRY_SIZE_NOT_PENDING_SQL, selectNotPendingSizeStatement);

View on GitHub (pinned to eb14a895d8)

Solutions

  1. Clear the cache to reset the journal and eliminate any duplicated/inconsistent rows.
  2. Confirm only one EvictionManager/disk-cache instance operates on the directory concurrently.
  3. Upgrade the sqljournaldiskcache integration for concurrency fixes around delete.
  4. If reproducible, capture the key, expected size, and actual deleted count from the message and file a bug.
Defensive patterns

Strategy: fallback

Try / catch

try {
  diskCache.delete(key)
} catch (e: IllegalStateException) {
  if (e.message?.contains("Failed to delete entry") == true) {
    // row already gone or duplicated; clear to reset consistent state
    diskCache.clear()
  } else throw e
}

Prevention

When it happens

Trigger: selectNotPendingSizeStatement confirms the key is present (isKeyPresent true), but the subsequent deleteEntryStatement.executeUpdateDelete() returns a count != 1, so the guard at line 307 fires.

Common situations: A race where the row was removed between the presence check and the delete; duplicated rows from a prior partial write; concurrent eviction and put operating on the same key; a journal corruption causing the presence query and delete to disagree.

Related errors


AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14). Data as JSON: /api/errors/29a72d27229a722a. Report an issue: GitHub.