‘Saved!’ toast on a profile save that failed with 409
The toast and the reset form both say success, and nothing reaches the console. The edit is simply gone the next time the page loads.
account-centerFound 2026-10-19Full report in Replay QA
What the recording showed
PATCH /api/profile returned 409 {"error":"Profile was modified since it was loaded"}. handleSubmit never checks res.ok, and a logpoint on setVersion showed the success path running on the 409 response.
Actual
Clicking "Save changes" shows a green "Saved!" toast in the bottom-right even though the PATCH request fails with HTTP 409. The edits (bio "Owns the onboarding pipeline and quarterly vendor reviews. Now leads vendor reviews end to end.") are treated as saved — the form's dirty state is reset — but they are not persisted, and the profile header continues to show a stale "Last updated 15m ago" instead of "just now".
Expected
When the PATCH /api/profile request returns a non-2xx status (409 Conflict), the app must NOT report success: it should surface the conflict error (e.g. "Profile was modified since it was loaded"), keep the user's typed edits in the form so they can resolve the conflict, and not show a "Saved!" confirmation. Only a successful 2xx response should clear the dirty state and refresh the header's "Last updated" status.
Session replay
Chronology of events

0:08.7On the Account Center Profile page, the user clicks the 'Save changes' button (button type=submit) in the Personal information section. The frame shows the form with Job title 'Operations Director', the edited Bio, the enabled Save changes button, and the header still reading 'Last updated 15m ago'.
2 evidence probes (PlaywrightSteps, InspectElement)
PlaywrightSteps {"mode":"step-detail","stepNumber":512}
→ Step 512: locator.click
============================================================
Time: 86258ms
Duration: 28ms
API: locator.click
Category: command
Params: {"selector":"html:nth-of-type(1) > body:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(1) > main:nth-of-type(1) > div:nth-of-type(1) > form:nth-of-type(1) > div:nth-of-type(3) > button:nth-of-type(2)","strict":true,"timeout":3000}
Stack trace:
at invoke scripts/journey/run-script.bundle.cjs:21788:40
at scripts/journey/run-script.bundle.cjs:21811:62
at recordOperation scripts/journey/run-script.bundle.cjs:87762:30
at scripts/journey/run-script.bundle.cjs:21811:22
Inspector Commands (11):
------------------------------------------------------------
[86260ms, point: 122992531837815596714131762570074558] Runtime.callFunctionOn (id: 2719)
params: {"functionDeclaration":"(utilityScript, ...args) => utilityScript.evaluate(...args)","objectId":"-4280474253936279394.4.2","arguments":[{"objectId":"-4280474253936279394.4.2"},{"value":true},{"value":false},{"value":"(injected, { info, callId }) => {\n const elements = injected.querySelectorAll(info.parsed, document);\n if (callId)\n injected.markTargetElements(new Set(elements), callId);\n const element3 = elements[0];\n let log3 = \"\";\n if (elements.length > 1) {\n if (info.strict)\n throw injected.strictModeViolationError(info.parsed, elements);\n …InspectElement {"point":"Point:11","element":"main form div:nth-of-type(3) button:nth-of-type(2)"}
→ Element:1 is `<button type="submit" class="button"></button>`.
Element:1 is rendered by React component ProfileSection at Point:19:
Relevant code: http://localhost:3205/src/pages/Profile.jsx line 107 column 8
No elements are obstructing the center point of this element.
Element:1 has 127.390625px width and 36px height.
Margin: top 0px right 0px bottom 0px left 0px.
Padding: top 9px right 16px bottom 9px left 16px.
Distances to its parent element:
- Top overflows parent by 17.00px
- Right is aligned with parent boundary
- Bottom is aligned with parent boundary
- Left overflows parent by 794.61px
### Parent Element:2
Element:2 is `<div class="panel-actions"></div>`.
Element:2 is rendered by React component ProfileSection at Point:20:
Relevant code: http://localhost:3205/src/pages/Profile.jsx line 103 column 6
Element:2 has 922px width and 53px height.
Margin: top 18px right 0px bottom 0px left 0px.
Padding: top 16px right 0px bottom 0px left 0px.
Distances to its parent element:
- Top overflows parent by 330.00px
- Right overflows parent by 23.00px
- Bottom overflows parent by 23.00px
- Left overflows parent by 23.00px
### Parent Element:3
Element:3 is `<form class="panel"></form>`.
Element:3 is rendered by React component ProfileSection at Point:21:
Relevant code: http://localhost:3205/src/pages/Profile.jsx line 74 column 4
Element:3 has 968px width and 406px height.
Margin: top 0px right 0px bottom 20px left 0px.
Padding: top 22px right 22px bottom 22px left 22px.
…The click sends the save: PATCH /api/profile with the edited bio and "version":2. The server answers 409 Conflict 66 ms later, {"error":"Profile was modified since it was loaded"}, so nothing was saved. This is the request the replay's DevTools opens on.

0:08.8A green 'Saved!' toast appears in the bottom-right corner while the profile header still reads 'Last updated 15m ago' (not refreshed to 'just now'). The PATCH /api/profile request actually failed with HTTP 409 and the edits were not persisted.
Steps to reproduce
Verify the starting page
Clear the Job title field and type a new job title
Type the new job title
Clear the Bio field and type a new bio
Type the new bio
Click the Personal information section's Save changes button
Root cause
In Profile.jsx, ProfileSection.handleSubmit (lines 51-71) never checks res.ok or the HTTP status: inside the try block it unconditionally does await res.json(), setVersion(updated.version), setInitial(values), queryClient.invalidateQueries(...), and toast('Saved!'). The catch block only fires on network-level failures. So when PATCH /api/profile returns 409 with body {"error":"Profile was modified since it was loaded"}, the code takes the success path: a Logpoint at line 61 (setVersion) shows res.status === 409 and updated === the error body at the moment of execution, and line 65 then shows toast('Saved!'). This yields a false success confirmation and discards the user's edits (setInitial(values) resets the dirty state).
3 evidence probes (Logpoint, NetworkRequest, SearchSources)
Logpoint {"line":61,"path":"http://localhost:3205/src/pages/Profile.jsx","expression":"({ line61_setVersion_updated: updated, resStatus: res.status })"}
→ Found 1 total hit at http://localhost:3205/src/pages/Profile.jsx:61
Hit 1 at point Point:18 @ 86467.05ms:
Expression: ({ line61_setVersion_updated: updated, resStatus: res.status })
Result: {
"line61_setVersion_updated": {
"error": "Profile was modified since it was loaded"
},
"resStatus": 409
}
NetworkRequest {"mode":"detail","requestId":"744.59"}
→ A PATCH network request with ID 744.59 was made to http://localhost:3205/api/profile:
<request_summary>
The response had status 409 (Conflict).
</request_summary>
Initiated at Point:3 @ 86278.00ms
Events:
request @ 86278ms
request-body @ 86278ms
response @ 86466ms
response-body @ 86467ms
request-done @ 86467ms
Request headers:
<requestHeaders>
sec-ch-ua:
Content-Type: application/json
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/108.0.5359.0 Safari/537.36
sec-ch-ua-platform:
</requestHeaders>
Response headers:
<responseHeaders>
keep-alive: timeout=5
date: Mon, 19 Oct 2026 23:43:24 GMT
connection: keep-alive
x-powered-by: Express
content-length: 52
etag: W/"34-go2K6deri6ziiR4tYLVppx0Ngxs"
content-type: application/json; charset=utf-8
</responseHeaders>
The request body was
:
<requestBody>
{"bio":"Owns the onboarding pipeline and quarterly vendor reviews. Now leads vendor reviews end to end.","version":2}
</requestBody>
The response body was
:
<responseBody>
{"error":"Profile was modified since it was loaded"}
</responseBody>
_Previous: `requestId: "744.58"` | Next: `requestId: "744.60"`_SearchSources {"pattern":"Saved!"}
→ ### http://localhost:3205/src/pages/Profile.jsx
hits | L | code
------|------|------
| 37 | function ProfileSection({ title, description, fields, profile }) {
1 | 64 | queryClient.invalidateQueries({ queryKey: ['account'] });
1 | *65 | toast('Saved!');
| 66 | } catch {Root cause → actual behavior
The PATCH /api/profile request made at 86278ms returns HTTP 409 with response body {"error":"Profile was modified since it was loaded"} (request body carries version:2 and the edited bio).
1 evidence probe (NetworkRequest)
NetworkRequest {"mode":"detail","requestId":"744.59"}
→ A PATCH network request with ID 744.59 was made to http://localhost:3205/api/profile:
<request_summary>
The response had status 409 (Conflict).
</request_summary>
Initiated at Point:3 @ 86278.00ms
Events:
request @ 86278ms
request-body @ 86278ms
response @ 86466ms
response-body @ 86467ms
request-done @ 86467ms
Request headers:
<requestHeaders>
sec-ch-ua:
Content-Type: application/json
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/108.0.5359.0 Safari/537.36
sec-ch-ua-platform:
</requestHeaders>
Response headers:
<responseHeaders>
keep-alive: timeout=5
date: Mon, 19 Oct 2026 23:43:24 GMT
connection: keep-alive
x-powered-by: Express
content-length: 52
etag: W/"34-go2K6deri6ziiR4tYLVppx0Ngxs"
content-type: application/json; charset=utf-8
</responseHeaders>
The request body was
:
<requestBody>
{"bio":"Owns the onboarding pipeline and quarterly vendor reviews. Now leads vendor reviews end to end.","version":2}
</requestBody>
The response body was
:
<responseBody>
{"error":"Profile was modified since it was loaded"}
</responseBody>
_Previous: `requestId: "744.58"` | Next: `requestId: "744.60"`_Despite the 409, handleSubmit executes the success path: the Logpoint at line 61 fires with resStatus 409 and updated equal to the error body, and line 65 runs toast('Saved!') unconditionally (no res.ok guard exists between them).
2 evidence probes (Logpoint, SearchSources)
Logpoint {"line":61,"path":"http://localhost:3205/src/pages/Profile.jsx","expression":"({ line61_setVersion_updated: updated, resStatus: res.status })"}
→ Found 1 total hit at http://localhost:3205/src/pages/Profile.jsx:61
Hit 1 at point Point:18 @ 86467.05ms:
Expression: ({ line61_setVersion_updated: updated, resStatus: res.status })
Result: {
"line61_setVersion_updated": {
"error": "Profile was modified since it was loaded"
},
"resStatus": 409
}
SearchSources {"pattern":"Saved!"}
→ ### http://localhost:3205/src/pages/Profile.jsx
hits | L | code
------|------|------
| 37 | function ProfileSection({ title, description, fields, profile }) {
1 | 64 | queryClient.invalidateQueries({ queryKey: ['account'] });
1 | *65 | toast('Saved!');
| 66 | } catch {Because setInitial(values) resets the form to the typed (unsaved) values, the app shows the stale 'Saved!' confirmation and the profile header keeps its old 'Last updated 15m ago' text — an Evaluate at the save point measured the header still reading 'Last updated 15m ago' with the unsaved bio present in the textarea.
1 evidence probe (Evaluate)
Evaluate {"point":"Point:11","scope":"global","expression":"(() => { const all = [...document.querySelectorAll('*')]; const lastUpd = all.find(el => el.children.length === 0 && /Last updated/.test(el.textContent || '')); const bio = document.querySelector('textarea'); return { lastUpdated: lastUpd ? lastUpd.textContent.trim() : null, bioValue: bio ? bio.value : null }; })()"}
→ {
"lastUpdated": "Last updated 15m ago",
"bioValue": "Owns the onboarding pipeline and quarterly vendor reviews. Now leads vendor reviews end to end."
}Is your app hiding bugs like this?
Replay QA explores every build, records what it finds, and writes the root cause.