June 15, 2026 ยท 3 min read
Resuming persisted mutations in TanStack Query
How Codex fixed an offline checkout mutation that stopped working after reload.
We tested a React checkout flow that uses TanStack Query persistence. A customer places an order offline, the mutation pauses, and the app saves the query cache. After a reload, the app restores the cache and calls resumePausedMutations().
The order should be submitted once. Instead, nothing happened.
Both runs used Codex GPT-5.5 against @tanstack/react-query 5.101.0 and @tanstack/react-query-persist-client 5.101.0 with the same prompt:
Fix this TypeScript React fixture so `npm test` and `npm run typecheck` succeed, preserving queued checkout writes across app reloads.
Case study replayReal agent replays
TanStack Query persisted checkout outbox
model Codex GPT-5.5Fix this TypeScript React fixture so `npm test` and `npm run typecheck` succeed, preserving queued checkout writes across app reloads.
Without GitHits
- tokens
- 0
- time
- 0s / 126s
- Ready. Click "Watch Replay" to start.
- Reached the same mutation-default fix, but first installed dependencies and reconstructed the persistence path from local TanStack Query internals.
With GitHits
- tokens
- 0
- time
- 0s / 79s
- Ready. Click "Watch Replay" to start.
- Used TanStack Query persistence docs to register a keyed mutation default, allowing hydrated paused checkout writes to resume after reload.
Result
| Run | Time | Tokens | Tools |
|---|---|---|---|
| With GitHits | 79s | 350,965 | 19 |
| Without GitHits | 126s | 1,031,661 | 35 |
Both runs produced a passing patch. The GitHits run used 680,696 fewer processed tokens and 16 fewer tool calls.
Why the mutation stopped
The fixture created a QueryClient without mutation defaults:
export function createCheckoutClient(_api?: CheckoutApi): QueryClient {
return new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
}
The component supplied the function when it called useMutation:
const submitOrder = useMutation({
mutationKey: submitOrderMutationKey,
mutationFn: api.submitOrder,
});
That function belongs to the mounted component. The persisted mutation keeps its key and state after reload, but not the component closure. TanStack Query needs a default mutation function for the same key before it can resume the work.
The fix
The patch registered the submit function on the client:
export function createCheckoutClient(api?: CheckoutApi): QueryClient {
const client = new QueryClient({
defaultOptions: {
queries: { retry: false },
mutations: { retry: false },
},
});
if (api) {
client.setMutationDefaults(submitOrderMutationKey, {
mutationFn: api.submitOrder,
});
}
return client;
}
The test restores the offline write into a fresh client, goes online, resumes paused mutations, and checks that the API receives the original order once.
What GitHits changed
Both runs found the same fix. The GitHits run finished 47 seconds sooner, used 680,696 fewer processed tokens, and needed 16 fewer tool calls.
GitHits found the persistence guide for TanStack Query 5.101.0. It states the missing requirement directly: after hydration, a paused mutation can only resume if the client has a default mutation function for its key. Codex could then add setMutationDefaults, run the tests, and typecheck the fixture.
Without GitHits, Codex installed the dependencies and traced the rule through hydration, mutation cache, query client defaults, and mutation option code. The final patch was identical, but GitHits replaced that source-level investigation with one version-matched documentation path.