Two Bugs That Only Korean Files Could Find
One character wrong in a PDF title, and two days to explain it. “latin1” does not mean Latin-1, and your test fixtures are a demographic statement.
Date
Category
Writer

A PDF arrived and the product reported its title as RAR 2026 시쥒 브리프.
The real title was RAR 2026 시즌 브리프. One character wrong. Just the one, in the middle of an otherwise perfect string.
That single character cost two days, and the two bugs behind it are, I think, the most useful thing I have found all year, because neither was catchable by any test I would have thought to write.
Bug one: "latin1" does not mean Latin-1
The reader was decoding bytes with this:
Which any reasonable person reads as ISO-8859-1. It is not.
Per the WHATWG Encoding Standard, the following labels all map to windows-1252:
The specification even includes a note acknowledging the confusion directly, observing that these labels have historically been confusing for developers and that on the web, "latin1" and "ascii" are just labels for windows-1252.
The history is straightforward once you know it. Both ISO-8859-1 and ASCII leave part of the byte range undefined or unused. Implementations filled that range in differently. Browsers converged on windows-1252 for compatibility, and the Encoding Standard then wrote the convergence down rather than pretending otherwise.
Where the difference actually lives
Byte range | ISO-8859-1 | windows-1252 | Same? |
|---|---|---|---|
0x00 to 0x7F | ASCII | ASCII | Yes |
0x80 to 0x9F | C1 control codes | Printable: quotes, dashes, €, ™ | No |
0xA0 to 0xFF | Latin-1 supplement | Latin-1 supplement | Yes |
Table 1. Thirty-two of 256 values differ. One byte in eight.
For English text you will never see this. Those bytes essentially do not occur in English content. For Korean text encoded in a byte-oriented format they occur constantly, and every one of them decodes to something near-plausible. Not garbage. Not an exception. Just a slightly different Korean character, in a slightly different word, inside a title that still reads like a title.
That is what makes it expensive. A crash is cheap. A wrong answer that looks like a right answer is not.
Bug two: PDF escapes non-ASCII in octal
With the first bug fixed, the title was still wrong, differently.
PDF string literals escape characters with backslashes. A reader written by someone who has only ever handled English PDFs will handle the obvious three and stop:
Every non-ASCII character in a PDF string can arrive in that form. A reader that ignores octal escapes will mangle every title that is not in English, and will do it in a way that produces output rather than an error, which means nothing anywhere reports a problem.
Why neither was findable
This is the part I actually want to write about.
The project had 316 unit tests when these shipped. Neither bug was catchable by any of them, and no quantity of additional tests of the same kind would have helped, because the tests ran against fixtures, and I wrote the fixtures.
I wrote English filenames because I write code in English. I generated test PDFs with ASCII titles because that was the path of least friction at the moment I needed a fixture. Every fixture encoded, invisibly, an assumption about who the user is.
Your test fixtures are a demographic statement. They describe the user you were imagining when you wrote them.
Both bugs surfaced the first time a real Korean file went through a real browser. Not a generated one. A real document, with a real title, from real work, dropped in by a person who wanted to keep it.
The fix at the fixture level was to make the generator produce material that looks like the material the product will actually receive: Korean filenames, emoji, overlong names, mixed scripts, files whose declared type is wrong. That generator now runs on a fresh clone, so the rehearsal is real rather than a recording.
The instrument bug, which is worse
There is a coda, and it is the one I would most want another builder to know about.
While writing browser tests to cover this, Playwright's setInputFiles silently dropped every file whose name was not ASCII. No error. No exception. No change event. No files.
The test simply asserted against an empty state, and the empty state was, technically, exactly what the page showed.
So for a while, the tests designed to catch the Korean encoding bugs were themselves structurally unable to deliver a Korean file.
The lesson generalises well past this one API:
When a test proves nothing, suspect the instrument before you suspect the code.
A green suite that cannot deliver the input it claims to be testing is not weak coverage. It is a false statement, and it is stated in the most confident typography your CI has. Every other signal in the system agrees with it.
The general version
Three things I took from two days:
A wrong answer is more expensive than a crash, and systems that produce plausible output on malformed input are optimised for the wrong failure. The octal bug and the encoding bug both produced strings. Neither produced an error.
Fixtures encode assumptions you do not know you hold. Not values, not opinions. Defaults so deep they were never decided. The only reliable way to surface them is to run real material from a context other than your own.
Test infrastructure is code, and it fails. We treat the harness as ground truth because it is the thing that tells us about truth. It has bugs at the same rate as everything else, and its bugs are worse, because they fail toward false confidence.
The character was 즌 becoming 쥒. Everything above came out of that.
Sources
WHATWG Encoding Standard, the encodings table and the note on legacy labels. encoding.spec.whatwg.org
Related reading
Latest Articles.
© Moc Mallen Studio
Thoughts, ideas, and perspectives on design, simplicity, and creative process.

