Day 134: The Message That Erased Itself
Here is a bug that feels like the software gaslighting you. You send a message with an image to an agent, you tab away, you come back a few minutes later, and your message is gone. Not the reply, the reply is right there. Your own turn, the thing you typed, has vanished from the thread. It looks exactly like data loss, which is the worst thing a tool people trust with their work can look like.
The transcript was fine the whole time
It wasn’t data loss. The on-disk session file had the message the entire time. I verified that against real OpenClaw output on staging by reading the gateway’s own history over its local RPC (PR #637). The failure was in the reading, not the writing, and it was a chain of three innocent-looking links.
OpenClaw’s chat.history RPC caps a single message at 128 KB. An inline image routinely blows past that. When it does, the RPC replaces the whole oversized message with a fixed placeholder string, throwing away the original text and the <pinchy:attachments> marker embedded in it. Then Pinchy’s own parser ran a regex to strip the leading timestamp off each message, and on that particular placeholder the regex reduced it to an empty string. Finally, the filter that drops empty, file-less rows did its job and dropped it. Three correct-in-isolation steps, and the user’s turn evaporated from the view while sitting safely on disk. The assistant’s reply survived only because it was small enough never to trip the cap.
The fix keeps the user’s message instead of letting the size cap eat it, and it is the kind of bug I’m glad lived on staging and not in someone’s real thread. This is the same disease I wrote about on Day 120: the agent was alive, the work was done, and only the display told a lie. A tool people run themselves has to be trustworthy about its own record of what happened, and “your message is gone” is the single most corrosive lie it can tell.
Errors that know what kind of error they are
Two related fixes shipped the same day, both about errors being honest. The durable error banner exists to re-surface a failure you might have missed, an intermittent one whose live bubble died on a reload. But it was firing for every error, including permanent ones, a retired model or a context overflow that will recur on every single attempt. Those can’t be missed, so the sticky banner just nagged and reappeared on every navigation, offering a Retry that could never work. Now a compile-checked switch over the error classes decides which failures are worth persisting (PR #634), only the retryable ones get the durable banner, and it finally has a Dismiss button. And generic model errors now name the model that failed (PR #632) instead of saying “LLM request failed” and leaving you to guess which of your agents’ models fell over.
Day 134
The thread through all three is the same: an error’s most valuable property is being honest, about what happened, whether it will happen again, and whether your data is actually gone or just not being shown. “Your message is gone” when it isn’t, “retry this” when retry is hopeless, “LLM request failed” when it could just say which one. None of these lost anybody’s work. All of them spent trust, which for a tool you run yourself is the only currency that matters.