Skip to content
Back to blog

Published on August 19, 2026 · 4 min read

The panel wrote "Saved" above content that was not in the database

You open two browser tabs of the panel. In one of them you delete a project. In the other, opened earlier, you change the deadline of that same project and click "Save". The panel writes "Saved".

It did not save. There was nowhere to save to.

Why the database does not object

UPDATE projects SET deadline = ... WHERE id = ... against a row that is already gone is a perfectly valid query. The database does exactly what it was asked: it scans the table, finds zero matching rows, changes zero rows and returns success. There is no error to report here — no match is not a failure, it is a result.

Code that looks like this:

await sql`UPDATE projects SET deadline = ${deadline} WHERE id = ${id}`;
return Response.json({ ok: true });

is always truthful in its ok: true. The query did succeed. It is just that "the query succeeded" and "the data is in the database" are two different sentences, and this code confuses them.

How I found it

Not in production — at home, during a dry run. I wrote a simple probe: for every kind of record in the panel, create it, delete it, then try to save a change as if a second tab were still open. Then check what the route answered.

The result: nine of sixteen record types answered {"ok":true}. Nine places where the panel would tell the user "Saved" above content that exists nowhere.

This is exactly the category of bug you will not find by clicking around. To hit it by hand you need two open tabs and you have to delete the record precisely between the load and the save. With one person and one tab that scenario never happens — until the day it does.

The fix is smaller than it looks

The reflex says: "let us first check whether the record exists" — that is, add a SELECT before every UPDATE. That would mean one more query on every single save across the whole panel.

It turned out that in most places that SELECT was already there. The main records read their own state before saving anyway, because they keep a change log ("what changed from what to what"). It was enough to use the result that was already sitting in a variable:

const before = await fetchRecord(id);
if (!before) return missingRecordResponse("project");

One conditional, zero new queries. Where the read genuinely was not there, one was added — and that is a price worth paying so that the message does not lie.

One deliberate exception

DELETE did not get this. Removing something that is already gone ends in exactly the state that was asked for: the thing is not there. A "not found" message would be formally correct here and pointless in practice — the user wanted the record gone, and the record is gone.

That asymmetry matters more than it looks: rules are worth applying where they change something, not everywhere because they are a rule. Adding the check to DELETE for the sake of consistency would look like tidiness while producing error messages in situations where nothing bad happened.

What this does not fix

The change does not resolve the collision of two tabs — it merely stops lying about it. If somebody in the other tab edited the record instead of deleting it, my save still overwrites their work. Deliberately: this is a system for one person, and concurrency control would be a cannon aimed at a sparrow.

But one thing changed here too — the divergence stopped being invisible. The tab attaches a timestamp from the moment it loaded the record, and the server compares it with the current one. If they differ it saves anyway, but adds a sentence to the response saying that somebody touched this record in the meantime. The distinction sounds pedantic and it is the whole difference between "the system got it wrong" and "the system warned me and I decided".

The conclusion I take further

The most dangerous bugs in office systems do not crash the application. They answer "done". An invoice that "went out" and did not; an address that was "saved" and stayed the old one; an order confirmed in the system and absent from the warehouse. For five years of running an office I saw this class of problem from the other side — as "but I typed that in yesterday". Now I know what it looks like from the inside.

Since I checked this, I treat every success message as a claim to be proven: on what grounds did this text appear? If the answer is "because the query did not throw an error", that is not enough.

Patryk Piecyk

Patryk Piecyk

Warsaw · junior implementation consultant · available now

For seven and a half years I worked at a German company, five of them running its office: orders, invoices, complaints, ERP. Since June 2026 I have been building my own tools for that same work — I am not a programmer by training; the code is written together with an AI assistant, while the design, the decisions and the testing are mine. These notes describe what broke in those systems and what came out of it.

Got a question about this piece?

Write to me