Tokenizer quirks

A model never sees letters or digits, only token IDs. That one fact explains a surprising list of failures: shaky arithmetic, miscounted letters, words that change meaning with a space or a capital letter, and “glitch tokens” that made GPT-3 behave strangely. Here are real examples from seven tokenizers.

Key idea
The model sees token IDs, not characters: numbers split irregularly, letters are hidden inside tokens, “cat” ≠ “ cat” ≠ “Cat”, and rare tokens can be left untrained
Real world
Reading a sentence printed as a row of shorthand symbols. You can learn that one symbol means “strawberry”, but if someone asks how many r’s it has, you have to remember the spelling, because you can’t see it.
In an LLM
In GPT-4o’s tokenizer “ strawberry” is a single token, ID 101830 when it follows a space. The model gets that one number. Counting the r’s means recalling, from training, which letters that number stands for.

The model sees IDs, not letters

The BPE page showed how a tokenizer cuts text into pieces from a learned list, and bytes showed how every text can be cut that way. What reaches the model is a list of ID numbers, one per piece. Each ID is turned into a vector by looking up a row of a table (the embeddings page shows how). Nothing in that vector says how the piece is spelled, how many characters it has or which digits it holds. The model can only learn such facts indirectly, from how tokens are used.

Most of the time that does not matter: the model learns that “ strawberry” is a red fruit, which is what you usually need. But whenever a task depends on the characters themselves, the tokenizer gets in the way. Below are seven real tokenizers, from GPT-2 (2019) to Qwen3.5 (2026), on the same texts.

Loading GPT-2 data…

Numbers

Digits are where tokenizers differ most, and there are three families:

  • Learned merges (GPT-2, GPT-3). Number tokens are whatever BPE found frequent: “ 2024” is one token because years are common, while 1234567 becomes 123|45|67. The same digits can split differently depending on their neighbours.
  • Groups of up to three, from the left (GPT-4, GPT-4o, Llama 3, DeepSeek-V3). Before BPE runs, the step cuts every run of digits into chunks of at most 3. All 1,000 three-digit strings are in the vocabulary, so 1234567 is always 123|456|7.
  • One digit per token (Llama 2, Gemma 3, Qwen3.5). Simple and regular, but a 12-digit number costs 12 tokens.

To add two numbers on paper you line up the digits by place value, starting from the right. Chunks counted from the left don’t line up when the numbers have different lengths. Try it:

GPT-4, GPT-4o, Llama 3, DeepSeek-V3
a
1234567
3 tok
b
89012
2 tok
a + b
1323579
3 tok
10⁶10³10⁰
pieces don’t line upa is 3 tokens, b is 2 tokens.
Groups of three are counted from the left, but place value is counted from the right. When the lengths differ, a box in a covers thousands while the box above it in b covers hundreds. The model must learn to undo this before it can carry.
Type two numbers (or press Random) and switch between the ways real tokenizers cut digits. Each coloured box is one token. Column addition needs the boxes of a and b to line up by place value.
example · adding in a foreign script

Imagine adding two numbers written in a notation where digits are grouped by a rule you don’t control: 1234567 is written as [123][456][7] and 89012 as [890][12]. Before you can add, you have to regroup both into units, tens, hundreds. That is extra work you can get wrong, and the fix is obvious: write 1,234,567 and 89,012, grouped from the right.

example · commas help GPT-4

Singh and Strouse (2024) gave GPT-3.5 and GPT-4 addition problems. With plain digits the tokenizer groups them from the left; with commas inserted (1,234,567) the groups run from the right and line up by place value. The commas alone improved accuracy a lot, and the errors without them followed the misaligned chunks. The tokenizer was visibly part of the problem.

Spelling: the strawberry problem

“How many r’s are in strawberry?” became famous in 2024 because many chatbots answered 2. The tokens explain why the question is hard. In GPT-4o, “ strawberry” after a space is one token. Without the space, it is st|raw|berry: three pieces, none of which is “just the r’s”. Either way the model has to recall the spelling of an ID rather than look at letters.

Models do learn a lot of spelling, because text contains spelled-out words, rhymes, acrostics and typos. But it is knowledge about the tokens, not perception of letters, and it is patchy for rare tokens. Today’s reasoning models often get the answer right by writing the word out letter by letter first: then each letter is its own token, and counting becomes easy. Changing the input so that the information is visible in the tokens is the same trick as the commas above.

Spaces and capitals

The leading space is part of the token. In GPT-2, “cat” at the start of a text is ID 9246, but “ cat” in the middle of a sentence is ID 3797, and “ Cat” is 5181. These are three unrelated rows in the embedding table; the model has to learn from data that they mean the same thing.

That has practical effects:

  • Prompts that end in a space. If your prompt ends with “The answer is ” (with a trailing space), the next token must be one that starts without a space, like “4” rather than “ 4”. Those tokens are rarer in that position, so the model can behave oddly. This is why prompt-writing guides warn against trailing spaces.
  • Capitals and shouting. “hello” and “ Hello” are single tokens, but “ HELLO” splits into “ HEL|LO” in GPT-4’s tokenizer. Text in capital letters takes more tokens and uses rarer ones.
  • Llama 2 adds a space at the start. Its SentencePiece tokenizer puts a space in front of the whole text, so “cat” at the very start becomes “ cat”, the same token as in mid-sentence. A text that really starts with a space then gets an extra space token: the lone · chip in the gallery.

Glitch tokens

In early 2023 Jessica Rumbelow and Matthew Watkins found a set of strange tokens in the vocabulary shared by GPT-2 and GPT-3, including “ SolidGoldMagikarp”, “ petertodd”, “ TheNitromeFan” and “ davidjl”. When asked to repeat “ SolidGoldMagikarp”, ChatGPT answered “distribute”. Other such tokens produced evasions, insults or nonsense, and some broke determinism even at temperature 0.

The explanation most people accept is a mismatch between two datasets:

  1. The tokenizer was trained on one big scrape of web text. Some Reddit usernames (several from r/counting, a forum where people count to infinity one comment at a time) appeared there thousands of times, so BPE gave each of them a single token.
  2. The model was trained on a different, filtered dataset where those strings almost never appeared.

A token that never appears in training never gets a useful embedding. Its row in the table stays close to where initialisation and weight decay left it, and the model has no idea what to do when it shows up. These are now called or under-trained tokens. Land and Bartolo (2024) built methods to find them automatically and found them in many open models.

You can see traces of this in GPT-2’s own embedding table. Among its 50,257 tokens, the ones whose embeddings sit closest to the average embedding include unused control characters, and strings like “ externalToEVA”, “quickShip”, “embedreportprint” and “ TheNitrome”: fragments of web-page boilerplate and usernames that were common when the tokenizer was built and rare in the training text.

Newer tokenizers split these strings into ordinary pieces (the gallery shows “ Solid|Gold|Mag|ik|arp”), and model builders now check for under-trained tokens. But any token that is rare in training is a weak spot; vocabulary size is partly a decision about how many rare tokens you can afford.

Code and whitespace

GPT-2 had one token per space, so a line indented by 12 spaces cost 11 tokens of indentation. Tokenizers built after code became a major use (GPT-4 onwards) have tokens for runs of spaces, for common symbols like “):” followed by a newline, and for combinations such as “(a”. The gallery’s Python example drops from 16 tokens in GPT-2 to 12 in GPT-4. Shorter sequences mean more code fits in the context and each step of generation does more.

example · phone autocorrect

Your phone’s keyboard learns whole words. It can be confidently wrong about a word it has seen once and knows nothing about strings it has never seen: type a rare username and it “corrects” it into something else. A glitch token is the model version: a vocabulary entry with almost no training behind it.

example · an LLM asked to reverse a word

Ask a model to reverse “strawberry” and it must split the single token into letters it cannot see, reverse them and produce tokens for “yrrebwarts”, a string it has probably never read. Models without step-by-step reasoning often get this wrong. Ask it to spell the word with spaces first (s t r a w b e r r y), and each letter becomes a token: now the reversal is easy.

going deeper

How digit splitting is implemented

The split into digit chunks is done by the pre-tokenizer, a regular expression applied before BPE. GPT-2’s pattern keeps a whole number together (with an optional leading space): ?\p{N}+. GPT-4’s cl100k_base pattern uses \p{N}{1,3}, which matches up to three digits at a time from the left, and drops the leading space from numbers. Llama 3 reuses this design. SentencePiece models such as Llama 2 and Gemma use split_digits, putting each digit in its own piece.

Finding under-trained tokens

Land and Bartolo use the output (unembedding) matrix: tokens that are never the right answer during training get pushed in a common direction, so their unembedding rows are unusually similar to each other and to known-unused tokens. They then confirm candidates by prompting the model to repeat them.

In papers

Related

  • bpe - BPE builds a vocabulary by starting from single characters and repeatedly merging the most frequent adjacent pair into a new token. The ordered list of merges is the tokenizer. To encode new text, cut it into chunks with a regular expression, then replay the merges inside each chunk.
  • bytes - Computers store text as Unicode code points packed into UTF-8 bytes, 1 to 4 per character. Byte-level BPE starts from the 256 possible bytes, so no text is ever unknown. The price is that scripts with more bytes per character, and less training data, cost many more tokens.
  • vocab-size - A bigger vocabulary packs more text into each token, so sequences get shorter and every language gets cheaper. But each extra token adds a row to the embedding table and a score the model must compute at every step, and rare tokens get too little training. Models moved from 32k–50k tokens to 128k–262k as they grew.
  • special-tokens - Some tokens are not text at all: they mark the start and end of a text, fill out batches, and separate the turns of a conversation. A chat is turned into one flat stream of tokens by a chat template, and the model only behaves like an assistant if that template matches the one it was trained on.