Skip to content

fix(query-persist-client-core/createPersister): await 'storage.setItem' when persisting a query - #11410

Open
MaxFreedomPollard wants to merge 1 commit into
TanStack:mainfrom
MaxFreedomPollard:fix/persister-await-set-item
Open

fix(query-persist-client-core/createPersister): await 'storage.setItem' when persisting a query#11410
MaxFreedomPollard wants to merge 1 commit into
TanStack:mainfrom
MaxFreedomPollard:fix/persister-await-set-item

Conversation

@MaxFreedomPollard

@MaxFreedomPollard MaxFreedomPollard commented Sep 6, 2026

Copy link
Copy Markdown

🎯 Changes

persistQuery in packages/query-persist-client-core/src/createPersister.ts awaits serialize but not storage.setItem, so the promise it returns resolves as soon as the write is started rather than when it finishes. This adds the missing await.

Two things go wrong with an asynchronous storage such as React Native AsyncStorage or idb-keyval. First, await persister.persistQueryByKey(queryKey, queryClient) returns before the entry is actually in storage, which matters because the createPersister docs show that call being used inside onMutate to persist an optimistic update. Second, a write that rejects, a quota error for example, becomes an unhandled promise rejection instead of rejecting the promise the caller is awaiting.

createAsyncStoragePersister already awaits its storage.setItem call in packages/query-async-storage-persister/src/index.ts, so this makes the two persisters agree.

The existing tests miss this because their mock storage writes into a Map synchronously and then returns an already resolved promise, which hides the difference. The two tests I added to createPersister.test.ts use a storage whose write is gated on a promise the test resolves, and a storage whose write rejects. Both fail on main and pass with the one line change.

Verification, all from the repo root: pnpm nx run @tanstack/query-persist-client-core:test:lib goes from 55 passing to 57 passing, and the two new tests fail on unmodified main (the rejection one also surfaces the unhandled rejection there). pnpm nx run @tanstack/query-persist-client-core:test:eslint reports 0 errors and the 2 pre-existing no-shadow warnings on lines 275 and 323, which this change does not touch. pnpm nx run @tanstack/query-persist-client-core:test:types passes on TS 5.6 through 7.0. pnpm run test:lib, pnpm run test:types, pnpm run test:build, pnpm run build, pnpm run test:sherif, pnpm run test:knip and pnpm run test:docs all pass. pnpm exec prettier --check is clean on the three changed files.

✅ 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 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 operations now complete only after data is successfully written to storage.
    • Storage write failures are now correctly reported to callers instead of becoming unhandled errors.
  • Tests

    • Added coverage for delayed storage writes and write failures.

…m' when persisting a query

`persistQuery` in packages/query-persist-client-core/src/createPersister.ts
awaited `serialize` but not `storage.setItem`, so the promise it returns
resolved as soon as the write was started rather than when it finished.

Two consequences with an asynchronous storage such as React Native
AsyncStorage or idb-keyval. `await persister.persistQueryByKey(queryKey,
queryClient)`, which the createPersister docs show being used in `onMutate`
to persist an optimistic update, returned before the entry was in storage.
And a failing write, for example a quota error, surfaced as an unhandled
promise rejection instead of rejecting the returned promise.

`createAsyncStoragePersister` already awaits its `storage.setItem` call in
packages/query-async-storage-persister/src/index.ts.

Adding the `await` fixes both. The two new tests in
packages/query-persist-client-core/src/__tests__/createPersister.test.ts
cover the ordering and the rejection, and both fail without the change.
@coderabbitai

coderabbitai Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 9e816d10-ce31-4365-90ff-74523513a4cd

📥 Commits

Reviewing files that changed from the base of the PR and between 1893a96 and b3e9dd2.

📒 Files selected for processing (3)
  • .changeset/persister-await-storage-write.md
  • packages/query-persist-client-core/src/__tests__/createPersister.test.ts
  • packages/query-persist-client-core/src/createPersister.ts

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


📝 Walkthrough

Walkthrough

createPersister now awaits storage writes. persistQueryByKey resolves after persistence completes and rejects when storage rejects. Tests cover delayed writes and propagated errors. A patch changeset records the release.

Changes

Persisted storage write handling

Layer / File(s) Summary
Await storage writes
.changeset/persister-await-storage-write.md, packages/query-persist-client-core/src/createPersister.ts
persistQuery awaits storage.setItem. The changeset records the patch release.
Validate persistence completion and errors
packages/query-persist-client-core/src/__tests__/createPersister.test.ts
Tests verify that persistQueryByKey waits for asynchronous writes and rejects with the storage error.

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

Merge Risk: ⚪ Minimal · up to b3e9d

Persistence now completes only after storage writes finish, and storage write failures propagate to callers. The changed completion and error behavior is covered by focused tests, with no remaining merge-blocking risk.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the affected package, function, and primary fix: awaiting storage.setItem during query persistence.
Description check ✅ Passed The description explains the change, motivation, affected behavior, tests, verification results, release impact, and checklist status. It includes the required changeset information.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 2 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

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.

1 participant