TanStack/query · warning

Provided storage does not implement `entries` method. Remova

Error message

Provided storage does not implement `entries` method. Removal of stored entries is not possible without ability to iterate over storage items.

What it means

Dev-only error from `removeQueries` in `createPersister`. Removing persisted entries by filter requires iterating all stored keys; if `storage` lacks `entries()`, the operation cannot run and fails loudly in development (silently skipped in production).

Source

Thrown at packages/query-persist-client-core/src/createPersister.ts:357

            persistedQuery = await deserialize(value)
          } catch {
            await storage.removeItem(key)
            continue
          }

          if (exact) {
            if (persistedQuery.queryHash !== hashKey(queryKey)) {
              continue
            }
          } else if (!partialMatchKey(persistedQuery.queryKey, queryKey)) {
            continue
          }

          await storage.removeItem(key)
        }
      }
    } else if (process.env.NODE_ENV === 'development') {
      throw new Error(
        'Provided storage does not implement `entries` method. Removal of stored entries is not possible without ability to iterate over storage items.',
      )
    }
  }

  return {
    persisterFn,
    persistQuery,
    persistQueryByKey,
    retrieveQuery,
    persisterGc,
    restoreQueries,
    removeQueries,
  }
}

View on GitHub (pinned to 159982c80b)

Solutions

  1. Implement `entries()` on the storage so the filter can scan all keys.
  2. Use a storage with native enumeration support (`localforage`, `Map`).
  3. Remove entries by explicit key with `storage.removeItem(prefix + hashKey(queryKey))` instead of the bulk filter.
  4. Decide whether production's silent skip is acceptable for your use case.

Example fix

// before
const persister = createPersister({ storage: asyncStorage })
await persister.removeQueries({ queryKey: ['todos'] })
// after
const storage = { ...asyncStorage, entries: async () => { /* return [k,v] pairs */ } }
const persister = createPersister({ storage })
await persister.removeQueries({ queryKey: ['todos'] })
Defensive patterns

Strategy: validation

Validate before calling

function assertCanRemove(storage: any) {
  if (!storage || typeof storage.entries !== 'function') {
    throw new Error('removeQueries needs storage.entries()')
  }
}

Type guard

const canEnumerate = (s: any): s is { entries(): Promise<Iterable<[string, any]>> } =>
  !!s && typeof s.entries === 'function'

Try / catch

try { await persister.removeQueries({ queryKey }) } catch (e) { if (/entries method/.test((e as Error).message)) console.warn('remove skipped:', e.message) }

Prevention

When it happens

Trigger: Calling `removeQueries()` (or the persister's bulk-remove path) with a storage that does not implement `entries()`; custom minimal storage adapters; passing a storage stub in tests.

Common situations: AsyncStorage variants; partial polyfills; test doubles that only mock `getItem`/`setItem`/`removeItem`; adapters targeting a key-value interface without enumeration.

Related errors


AI-assisted analysis of TanStack/query@159982c80b (2026-08-12). Data as JSON: /api/errors/38d07e3a10039482. Report an issue: GitHub.