2026-07-16 · 5 min · 960 words

Nothing Past the Zero

databasesinterface-designrepresentationsqlite

Insert ‘abc’, then a NUL byte, then ‘xyz’, into a SQLite text column. Ask the database how long the string is and it says 3. Ask it to show you the string and it shows you ‘abc’. Cast the same value to a BLOB and seven bytes appear: the x, y, and z were there the entire time. Query for rows where the column equals ‘abc’ and you get nothing, because the engine running the comparison knows the string is seven characters long. Only the tools built to describe the string to a human (length(), quote(), the command-line dump) stop counting at the zero. SQLite’s own documentation calls this “surprising” and adds, almost apologetically: “This seems like a bug. But it is how SQLite works.”

The zero (NUL, 0x00) is a leftover convention from C. A string there isn’t a value with a recorded length; it’s a run of bytes that a reading function walks through until it hits a zero, then stops. SQLite doesn’t store strings that way: it stores a value and a length, which is why the comparison in the WHERE clause gets the right answer. But the moment SQLite hands that value to something built on C’s older assumption (a formatter, a CLI display line), the length disappears and the zero becomes the whole story. Two different definitions of “where the string ends” are living inside the same seven bytes, and only one of them ever gets reported.

Thirty years earlier, in a paper nobody would shelve next to a database manual, Don Gentner and Jakob Nielsen ran into the identical shape from the opposite direction. Their 1996 essay “The Anti-Mac Interface” picks apart the Macintosh’s design principles one by one, and the one they save their sharpest words for is WYSIWYG. “The problem with WYSIWYG,” they write, “is that it is usually equivalent to WYSIATI: What You See Is All There Is.” A word set in italics might be there for emphasis, because it’s a book title, or because it’s a quotation; on the printed page, all three collapse into the same slanted letters, and whichever one the author meant is gone. A screen reader built for a blind user hits the same wall from underneath: it can only read “from the pixels on the screen without knowing what they mean,” because the pixels never held the meaning. The visual convention discarded exactly the information a blind reader would need restored.

Neither team read the other’s work. A 1996 interface-design paper and a 2026 database troubleshooting page have no citation between them and no shared audience: one was written for people arguing about desktop metaphors, the other for people debugging a WHERE clause. But they land on the same failure precisely enough that both reach for the same phrase to name it, unprompted: the thing you’re looking at is not the thing that exists. In both cases a system holds a richer, better-specified value (a length-counted string, an author’s italicizing intent), and a second system, built to present that value for inspection, encodes a narrower rule for where the value stops or what it means. The narrower rule wins the display, and nothing in the output marks that a disagreement happened. You only find out by asking a different question of the same data: cast it to a BLOB, or ask the author what they meant.

That’s also where the two cases stop rhyming. SQLite’s loss is recoverable because nothing was thrown away: the seven bytes sit intact on disk the whole time, and instr(X, char(0)) will find the zero the moment you think to ask. The bug is entirely in the reporting layer; the ground truth was never in danger. The Anti-Mac case has no such backstop. The reason for the slant isn’t sitting nearby waiting to be cast into a different format; it existed only in the author’s head at the moment of formatting, and WYSIWYG never asked them to record it anywhere else. Gentner and Nielsen’s proposed fix wasn’t a diagnostic flag; it was a different representation from the start: SGML-style markup that tags a string as a book title or a quotation and lets the rendering rule get decided later, per audience, from that tag. Nobody would propose casting a scanned page to a BLOB, because there’s no BLOB underneath it. The information a truncation bug merely hides, a WYSIWYG document never collected in the first place.

That gap gives a way to tell the two failure types apart before spending any effort chasing a fix: check whether a lower-level accessor already exists somewhere in the same system that recovers what the display dropped. SQLite has one. CAST(x AS BLOB) and instr(x, char(0)) mean anyone who wants the real value can get it without touching the engine’s storage or comparison logic at all, only the functions that print. A WYSIWYG editor has no equivalent to add, because there was never a second, richer layer underneath the printed page for such an accessor to expose. If a bug report says there should be a way to see the real data, the presence or absence of that way is the whole diagnosis: present, and the fix is a patch to the reporting layer; absent, and the fix is a new format, not a flag.

The ordinary advice, “look under the hood,” only works for one of these problems. SQLite’s zero is a courtesy the machine extends: everything survives, and any tool willing to ask a second, more literal question gets the real answer. The Anti-Mac’s italics grant no such courtesy. The render was the only place the information was ever going to live, and once it’s rendered, asking harder doesn’t help, because there was nowhere else for the meaning to have been kept.

adjacent