Stop Lost Updates with Version Checks
When two people edit the same record at once, whoever saves last silently overwrites the other's change. No error appears on screen or in the logs, and a test that runs alone never sees it. The deciding factor is whether you suspect "this can be touched concurrently" while you are still implementing.
Three classic lost-update patterns
1. Read, then write
The save sends back the values as they were when the edit screen opened. Alice opens the form, Bob saves, Alice saves, and Bob's change is gone.
2. Counter increments
Implemented as "read the value, add one, write it back", two simultaneous requests produce only one increment. Like counts, stock levels and ID numbering are typical victims.
3. Reordering a list
If the whole ordered array is saved, an item someone else just added disappears the moment the reorder is saved.
Fix 1: optimistic locking with a version number
Give each row a version number and update only if it still matches the version you read.
UPDATE tasks
SET title = :title, version = version + 1
WHERE id = :id AND version = :version_at_read;
-- 0 rows updated means someone saved firstWhen zero rows are updated, do not overwrite. Return HTTP 409 and tell the user "Someone else updated this first. Please review the latest version." In Rails, adding a lock_version column gives you the same behavior.
Fix 2: atomic updates
For counters, never read first. Let the database do the arithmetic.
UPDATE items SET stock = stock - 1
WHERE id = :id AND stock > 0;With stock > 0 in the condition, double purchases that would push stock below zero are blocked too.
Three questions to ask while implementing
- Is the value you save the one from when the screen opened, or a delta?
- Which screens or APIs let two people update the same row at once?
- On conflict, what does the user see: overwrite, rejection, or merge?
A two-tab reproduction check
- Open the same edit screen in two browser tabs
- Change the title in tab 1 and save
- Change a different field in tab 2 and save
- If tab 1's change survived, you pass. If it vanished, you have a lost update
For counters, click the same action rapidly from both tabs and check that the totals add up.
Putting it into practice with Bugoon
Concurrency bugs tend to be reported as "I saved it but it reverted", which is hard to reproduce from the words alone. With the Bugoon widget, the reporter can send a screenshot with annotations, the steps taken and console errors in one go. Reports land in GitHub Issues and the kanban board, so developers can see which screen it was and what happened just before. Being able to view reports from different reporters that arrived close together on the same screen side by side would make concurrency conflicts even easier to spot.
Streamline bug reporting for your team.
Bugoon is free to get started. Add one line of code to your site and transform how your team handles bugs.
Get Started