Skip to content

fix(query-persist-client-core): catch errors when persisting in 'persistQueryClientSubscribe' to prevent unhandled promise rejections, and log them in development - #11678

Open
kazbekaskarov wants to merge 1 commit into
TanStack:mainfrom
kazbekaskarov:fix/persist-subscribe-unhandled-rejection

Conversation

@kazbekaskarov

@kazbekaskarov kazbekaskarov commented Sep 26, 2026 •

Copy link
Copy Markdown

🎯 Changes

Fixes #11663.

persistQueryClientSubscribe dropped the promise returned by persistQueryClientSave, so a failing persister.persistClient (e.g. QuotaExceededError from IndexedDB) or a throwing dehydrateOptions callback caused an unhandled promise rejection on every cache update.

The subscription now catches these errors and, in development, logs them with console.error + console.warn, consistent with how persistQueryClientRestore reports restore errors.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested code changes locally with pnpm run test:pr, or these tests do not apply to this pull request.
  • I have followed the AI contribution policy and fully understand the code in this pull request, including any code generated with AI assistance.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is docs/CI/dev-only (no release).

Summary by CodeRabbit

  • Bug Fixes
    • Persistence errors during query updates are now caught and logged in development, preventing unhandled promise rejections. Errors during dehydration are also reported.

…istQueryClientSubscribe' to prevent unhandled promise rejections, and log them in development
@coderabbitai

coderabbitai Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: TanStack/query/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 7d7e932b-99b5-4d85-adf5-6c1b0c933ccd

📥 Commits

Reviewing files that changed from the base of the PR and between 66a7103 and a32315c.

📒 Files selected for processing (3)
  • .changeset/persist-subscribe-catch-save-errors.md
  • packages/query-persist-client-core/src/__tests__/persist.test.ts
  • packages/query-persist-client-core/src/persist.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.


📝 Walkthrough

Walkthrough

persistQueryClientSubscribe now catches errors from cache-triggered saves and logs them outside production. Tests cover rejected persistence and errors during dehydration.

Changes

Persistence save error handling

Layer / File(s) Summary
Catch and verify save errors
packages/query-persist-client-core/src/persist.ts, packages/query-persist-client-core/src/__tests__/persist.test.ts, .changeset/persist-subscribe-catch-save-errors.md
Cache subscriptions use a shared callback that catches save errors and logs them outside production. Tests cover rejected persistence and dehydration errors. The changeset records the update.

Priority: ⬇️ Low

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: ⚪ Minimal · up to a3231

Cache-triggered persistence failures are handled, and no merge-blocking issue is identified. The change is ready for normal checks.

Security Architecture Review

Security architecture risk: 🔵 Low · up to a3231

Save failures are now handled instead of becoming unhandled rejections. The change does not alter which cache events trigger saves or who controls persisted storage, but production callers still receive no indication that a save failed.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed failure handling applies to saves initiated by each subscribed query client and its supplied persister. The evidence does not establish the storage provider's scope or a broader deployment boundary.

Trust Boundaries and Controls

  • observed — The subscriber continues to filter cache events before invoking the existing save function. The change adds rejection handling rather than a new input route or storage authority.

Resilience and Maintainability Implications

  • observed — Subscriber save errors are logged in development but have no subscriber-level reporting path in production. Restore errors follow a separate path that performs cleanup and rethrows.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The change satisfies issue #11663. persistQueryClientSubscribe now attaches a rejection handler to every persistQueryClientSave call from query and mutation cache events. The handler prevents unha…
Out of Scope Changes check ✅ Passed The changes stay within issue #11663. The implementation updates save-error handling, the tests verify the required failure cases, and the changeset documents the same behavior. No unrelated product b…
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 1 functions across 2 files. (1 skipped: 1 …
Title check ✅ Passed The title clearly describes the main change: catching persistence errors in persistQueryClientSubscribe and logging them in development. It is specific, although longer than necessary.
Description check ✅ Passed The description includes all required sections, explains the motivation and implementation, completes the checklist, and documents the generated changeset for the published-code change.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@n-satoshi061

Copy link
Copy Markdown
Contributor

Thanks for picking this up! The fix looks correct to me for both paths (a rejecting persistClient and a throwing dehydrateOptions callback).

One thing that might be worth a maintainer's call: right now, a failed save in production at least surfaces as an unhandled rejection, which error trackers like Sentry pick up via onunhandledrejection. With this change, it's caught and nothing is reported in production, so the failure becomes completely silent there.

That may well be the right tradeoff. I just wanted to point it out, since the restore side isn't silent in production (it calls removeClient() and rethrows).

@kazbekaskarov

Copy link
Copy Markdown
Author

Hey guys! Can you check this PR please?
@lachlancollins @sukvvon

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants