Write down the smallest observable contradiction.
Use one request and its expected result. “Save is broken” is difficult to trace. “Saving version 7 returns 200, then an uncached read for this same account returns version 6” gives you a boundary to investigate.
Compare expected and actual JSON with JSON diff. Include record IDs, tenant scope and versions in your private investigation. Never make a public debugging endpoint that exposes another customer’s records.
const expected = { id: "report_1", version: 7, title: "October" };
const actual = { id: "report_1", version: 6, title: "September" };
const resultMatches = expected.id === actual.id
&& expected.version === actual.version
&& expected.title === actual.title;
console.assert(resultMatches === false);Compare a response that looks successful.
Download the expected report and actual response. Open each in JSON diff. Both are valid JSON and refer to the same record.
The comparison finds two changed paths. Expected JSON has /version 7 and /title October; Actual JSON has /version 6 and /title September. An HTTP status check would not establish whether those values were correct.
To fix a real case, establish whether the write committed first. If the database already has version 7, investigate the read path and cache. If it still has version 6, investigate the write. Returning a different status without correcting the state does not fix the customer's result.
Check the read and write use the same scope.
Follow the authenticated account, record ID and resource version through both requests. A successful write to a different workspace is a correctness and potentially a security problem. Authorisation must be enforced on the server for the specific resource.
If the record is correct in the database, inspect the response serializer, derived fields and whether a later update overwrote it. Do not fix an ownership mismatch by widening access.
Separate stale display from a failed write.
Reloading the whole page is a diagnostic step, not the final fix. Compare the immediate response, the browser cache and a fresh authorised read. Inspect your application cache keys and invalidation. Include tenant and permission context wherever responses differ by account.
Record whether the next read came from the primary database, a replica or an application cache. Do not assume every read observes the same point in time. Keep private responses out of shared public caches.
Test meaning, not only status.
Add an integration test that writes a known value and reads it through the same authorised route the UI uses. Also test the wrong-account request. A test that checks only response.ok would miss the contradiction in the example above.
Reference: MDN’s Fetch guide for response handling. Our local failure lab contains a passing-status, wrong-version case.