← All posts
BasicsAug 12, 2026

Why your search box cannot find a word you can clearly see

You paste a paragraph, look for a word you can see with your own eyes, and the search box comes back empty. The word is right there. Ctrl+F disagrees.

This is not a bug in your browser. There is a character sitting inside the word that has no width, no visible glyph, and no reason to exist in plain text. Your eyes skip straight over it. Your search box does not.

What is actually in the string

Take the word "helloworld" and run it through a character inspector after pasting it from a chat tool:

1 | hello▫world
  |      ^
  1:6  [error] zero-width character U+200B -> ""
       invisible; breaks string comparison and diffs

That is a stand-in the inspector draws so the character has something to point at on screen. In the actual file there is nothing there: hello, then U+200B ZERO WIDTH SPACE, then world. Eleven characters, not ten, and the sixth one renders as nothing.

Search for "helloworld" as one unbroken run and it fails, because the string you typed and the string in the document differ by exactly one character you cannot see. Word count, spell-check, and "select word" by double-click typically fail for the same reason: they read the string, not the picture your screen draws of it.

Paste three of these characters in a row and a checker reports them as a single finding spanning three characters, not three separate ones. The underlying rule collapses adjacent hits from the same cause into one run, which matters if you are trying to understand how many places actually need fixing versus how many characters need deleting.

Where it comes from

Zero-width space is the common one, but it is not the only character that does this. U+200C (zero-width non-joiner) and U+200D (zero-width joiner) do the same job of sitting between two visible characters with no rendered width. U+2060 (word joiner) and U+FEFF (byte-order mark, reused as a zero-width no-break space) are rarer but turn up too, usually from a copy out of a web page or a PDF export that embedded them for its own internal reasons.

None of these are unique to any one chat tool. They show up wherever text passes through a rendering pipeline that inserts its own invisible bookkeeping characters and then gets copied out as if it were plain text. The visible result looks identical either way, which is exactly the problem: there is no way to tell, by looking, whether the paragraph you just pasted is clean.

Non-breaking space (U+00A0) causes a related but distinct problem. It is not zero-width, so it does not split a word visually, but it is a different character from the ordinary space (U+0020) even though the two render the same. A search for an exact phrase that expects ordinary spaces will not match text that has a non-breaking space standing in for one of them.

Why you cannot just strip every invisible character

The tempting fix is a blanket rule: delete anything with zero visible width. That rule is wrong more often than you would expect, because some of these characters are not junk, they are load-bearing punctuation for scripts that are not Latin.

The same U+200D that is pointless junk sitting between two Latin letters is mandatory between two Devanagari consonants, where it changes which ligature gets rendered. Strip it indiscriminately and you have corrected an English typo by breaking a Hindi word. A character-by-character pass has to look at what sits on either side before deciding whether a given zero-width character is carrying meaning or is a paste artifact, which is the difference between a tool that cleans and one that quietly damages text it does not recognize.

Finding them without guessing

Because the whole problem is that these characters are invisible, "look at the text" is not a diagnostic step. What works is running the actual bytes through something that walks the string and reports every character with no visible glyph, showing you exactly where it sits and what it is. The cleaner on this site does exactly that: paste the paragraph in and it highlights each invisible character in place, with a tooltip naming the code point and a running count of what it removed, before you commit to changing anything. A command line version of the same engine exists for people who want to check a whole file at once, without giving an invocation here, since it is not part of what a visitor to this site can run directly today.

Both the on-page cleaner and that command line version read from the same underlying scan, so what one flags the other flags too, even though the two show it differently: the page renders highlighted segments with tooltips and a removed-character count, not a caret-and-label view line by line.

If you write a lot of text that started life somewhere else, that pass is worth running before the text goes anywhere a machine has to search, sort, or diff it exactly, because the moment it does, an invisible character in the middle of a word stops being cosmetic and starts being a bug report.