Skip to content

persistQueryClientSubscribe drops the persistQueryClientSave promise, causing unhandled rejections when persisting fails #11663

Description

@n-satoshi061

persistQueryClientSubscribe calls persistQueryClientSave(props) on every cache event, but it doesn't handle the returned promise. So if saving fails, I get an unhandled promise rejection on each cache update.

I noticed this while reading the code and confirmed it with a test. It can happen with a custom persister like the IndexedDB example in the docs, because set() from idb-keyval can reject, for example with QuotaExceededError or DataCloneError. It can also happen with the built-in persisters if a dehydrateOptions callback like shouldDehydrateQuery throws.

Small repro:

const queryClient = new QueryClient()

persistQueryClientSubscribe({
  queryClient,
  persister: {
    persistClient: () => Promise.reject(new Error('quota exceeded')),
    restoreClient: () => undefined,
    removeClient: () => undefined,
  },
})

queryClient.setQueryData(['a'], 1) // -> unhandled rejection

This affects all the persist providers, since they all use persistQueryClientSubscribe. That includes Vue's clientPersister when it's used with persistQueryClient().

The restore side already catches errors and logs a warning in dev (#8969), but the save side doesn't. I know error handling has mostly been left to the persister (#3527), so I'm not sure which way you'd prefer:

  1. catch it in persistQueryClientSubscribe and log in dev, same as restore
  2. keep the code as is, and add a try/catch to the IndexedDB example in the docs

I'm happy to send a PR for either one.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions