TanStack/query · warning

Provided storage does not implement `entries` method. Restor

Error message

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

What it means

Dev-only error from `restoreQueries` in `createPersister`. Restoring all queries needs to enumerate stored keys; without `storage.entries()` the bulk restore cannot proceed, so in development it throws. Filtered restores by `queryKey` would still work via direct key reads, but the unconditional path in this function requires iteration.

Source

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

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

          queryClient.setQueryData(
            persistedQuery.queryKey,
            persistedQuery.state.data,
            {
              updatedAt: persistedQuery.state.dataUpdatedAt,
            },
          )
        }
      }
    } else if (process.env.NODE_ENV === 'development') {
      throw new Error(
        'Provided storage does not implement `entries` method. Restoration of all stored entries is not possible without ability to iterate over storage items.',
      )
    }
  }

  async function removeQueries(
    filters: Pick<QueryFilters, 'queryKey' | 'exact'> = {},
  ): Promise<void> {
    const { exact, queryKey } = filters

    if (storage?.entries) {
      const entries = await storage.entries()
      const storageKeyPrefix = `${prefix}-`
      for (const [key, value] of entries) {
        if (key.startsWith(storageKeyPrefix)) {
          if (!queryKey) {
            await storage.removeItem(key)
            continue

View on GitHub (pinned to 159982c80b)

Solutions

  1. Add `entries()` to the storage adapter returning `[key, value]` pairs.
  2. Switch to a storage that natively supports enumeration (`localforage`, `Map`).
  3. If only specific keys need restoring, restore them manually via `retrieveQuery` per key instead of bulk `restoreQueries`.
  4. Verify in production builds the throw is skipped (dev-only) and decide whether silent skip is acceptable.

Example fix

// before
const persistor = new PersistQueryClientClient({ queryClient, persister: createPersister({ storage: asyncStorage }) })
await persistor.restore()
// after
const storage = { ...asyncStorage, entries: async () => { const keys = await asyncStorage.getAllKeys(); return Promise.all(keys.map(async k => [k, await asyncStorage.getItem(k)])) } }
const persistor = new PersistQueryClientClient({ queryClient, persister: createPersister({ storage }) })
Defensive patterns

Strategy: validation

Validate before calling

function assertCanRestore(storage: any) {
  if (!storage || typeof storage.entries !== 'function') {
    throw new Error('restoreQueries 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.restoreQueries(queryClient) } catch (e) { if (/entries method/.test((e as Error).message)) console.warn('restore skipped:', e.message) }

Prevention

When it happens

Trigger: Calling `restoreQueries(queryClient)` (or via the persist client plugin's restore-on-init) when the storage lacks `entries()`; using a storage adapter that only supports key-based access.

Common situations: React Native `AsyncStorage`; custom AsyncStorage adapters; minimal test stubs; legacy `localStorage` shims in older browsers/Node.

Related errors


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