Homelab hours are real hours.

title: TIL: The UI Said UTF-8. It Was Lying.
date: 2026-02-22 · 3 min read
type: til · tags: #linux #learning #macos #debugging

TIL: The UI Said UTF-8. It Was Lying.

Terminal.app showed the correct encoding. The terminal rendered garbage. The setting was stale.

I recently installed tmux on my current MacBook Air and the status bar showed Ã0Ã instead of [0]. Square brackets were rendering as garbled characters. So were tildes, backticks, and anything outside plain ASCII.

I assumed it was a tmux problem. Then a font problem. Then a locale problem. I checked $LANG (correct), $TERM (correct), the font (SF Mono — fine), the tmux config (clean ASCII). Nothing was wrong, but everything was broken.

Narrowing scope

I tried a different Terminal.app profile — opened a new window with the dark “Pro” theme. Pasted the exact same command. It rendered perfectly. Same machine, same shell, same tmux. Different profile, different result.

That pointed at the Terminal.app profile itself. I went to Settings > Profiles > Advanced and looked at the text encoding dropdown. It said Unicode (UTF-8). Correct. Obviously.

Except it was not.

The fix

I changed the encoding dropdown to something else, then changed it back to UTF-8. Opened a new terminal window. Everything rendered correctly. The brackets were brackets. The tildes were tildes. tmux looked normal.

Toggling the setting forced Terminal.app to write a fresh, known-good value to its preferences. Whatever was stored before — despite the UI showing “UTF-8” — was stale or corrupted.

Why the UI lied

The preferences dropdown is populated from a list of known labels. It matches on the name. The terminal’s rendering engine reads the stored value — a byte or identifier in a plist file. If the stored value drifts (a macOS update changes an internal enum, a preferences sync corrupts a byte, a migration carries forward a stale value), the UI can show the correct label while the runtime uses the wrong value.

It is the same principle as a config file that looks right in a text editor but has an invisible character — a BOM, a non-breaking space, a wrong line ending — that breaks the parser. What the human sees and what the machine reads are not always the same thing.

This is not new. Older versions of macOS had a well-known fix for misbehaving apps: delete the preference plist and let the system regenerate it. You lost your customizations, but it corrected problems that nothing else could explain. The fact that this workaround existed at all tells you something — preference files have always been fragile, and the UI has never been the final word on what they contain.

The uncomfortable truth

There is no good way to proactively catch this. You cannot toggle every UI setting on every app “just in case.” The only signal was the behavior: garbled characters that should not have been garbled. If I had not been paying attention — or if I did not know what correct output looked like — I would have blamed tmux, or blamed the font, or just lived with it.

A non-technical user would have seen garbage characters and either ignored them, assumed their computer was broken, or spent hours reinstalling things that were never the problem. The actual fix took five seconds, but finding it required:

  1. Noticing the behavior was wrong
  2. Knowing what “correct” looks like
  3. Isolating the variable (different profile worked, so it was profile-specific)
  4. Being skeptical of what the UI claimed

That is four skills that have nothing to do with tmux or encoding. They are general debugging skills: observe, compare, isolate, verify. And the hardest part was not trusting the UI that said everything was fine.

The lesson

“The UI says it is correct” is not the same as “it is correct.” Trust the behavior, not the label. When something is broken and every setting looks right, the setting itself might be the lie.

This applies everywhere: environment variables that are “set” but stale, config files that “look right” but have invisible corruption, cached values that the UI displays from memory while the system reads from disk. The gap between what is displayed and what is real is where the hardest bugs live.