Skip to content

fix(added-vocab): fix panic in single_word check - #2666

Merged
SBrandeis merged 5 commits into
huggingface:mainfrom
0z5a:fix/added-token-single-word-boundary
Nov 10, 2026
Merged

SBrandeis merged 5 commits into
huggingface:mainfrom
0z5a:fix/added-token-single-word-boundary

Conversation

@0z5a

@0z5a 0z5a commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #2664

is_single_word read the char before a match from s[search..match_start]. search is where the scan resumed, and that is not a word boundary:

  • After a rejected candidate it is match_start + 1. That can be inside a multi-byte char, so the slice panics.
  • It can be inside the same word: zz matches at 1..3 in zzz.
  • After an earlier added token it is that token's end: foo matches in xfoo.

This PR reads the char before the match from the whole text, as 0.23 does. The resume position after a rejected candidate is unchanged.

The new test, single_word_looks_before_where_the_scan_resumed, covers all three cases. Each assert fails on its own against main (the ü case panics), and all pass with this change. cargo fmt --check and clippy on tk-encode with -D warnings are clean.

With bert-base-multilingual-cased and the inputs from the issue, the Python results now match 0.23.3 on aarch64 and x86_64 Linux:

  • ко ##тик и кот
  • 111 11
  • Dr Smith ##field and Smithfield

I also checked single_word × lstrip × rstrip × normalized against 0.23.3 on six tokenizers (10 flag sets each). Main panics for 10 tokenizer/flag-set combinations; with this change there are none. The only differences left are the Metaspace ▁ from #2512 (T5, Mistral) and spans of tokens with rstrip, which this PR does not touch.

#2362 includes the same change inside a larger feature. This PR is just the fix and its test.

…he whole text

`is_single_word` read the char before a match from `s[search..match_start]`.
`search` is where the scan resumed, which is not a word boundary:

- after a rejected candidate it is `match_start + 1`, which can be inside a
  multi-byte char, and slicing there panics;
- it can be inside the same word (`zz` matched at 1..3 in `zzz`);
- after an earlier added token it is that token's end (`foo` matched in `xfoo`).

Read the char before the match from the whole text, as 0.23 did.

Signed-off-by: 0z5a <[email protected]>

@SBrandeis SBrandeis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch, thanks for fixing it
I left a few cosmetic comments, otherwise lgtm

@HuggingFaceDocBuilderDev

Copy link
Copy Markdown

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

0z5a and others added 3 commits November 10, 2026 16:35
@0z5a

0z5a commented Nov 10, 2026

Copy link
Copy Markdown
Contributor Author

Nice catch, thanks for fixing it
I left a few cosmetic comments, otherwise lgtm

Done

@SBrandeis SBrandeis changed the title fix(added-vocab): single_word looks at the char before the match in the whole text fix(added-vocab): fix panic in single_word check Nov 10, 2026
@SBrandeis
SBrandeis merged commit d30295c into huggingface:main Nov 10, 2026
29 of 30 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v1] AddedToken(single_word=True) panics on non-ASCII text and matches inside words

3 participants