Skip to content

fix: handle invalid decode ids in native binding - #65

Merged
AlonKejzman merged 4 commits into
crusoecloud:mainfrom
froststeam:fix/decode-sanitize-uint32
Aug 10, 2026
Merged

fix: handle invalid decode ids in native binding#65
AlonKejzman merged 4 commits into
crusoecloud:mainfrom
froststeam:fix/decode-sanitize-uint32

Conversation

@froststeam

Copy link
Copy Markdown
Contributor

Background

fastokens.patch_transformers() swaps the Hugging Face tokenizer backend for the native fastokens implementation.

The crash happens only when invalid decode IDs reach detokenization, for example negative sentinels or values larger than u32::MAX. In that case the native conversion path can raise:

OverflowError: out of range integral type conversion attempted

That should not take down the detokenizer process. The common case, where all token IDs are valid, should stay on the same fast path.

What changed

  • Kept the Python shim thin: it still forwards directly to _fast.decode() / _fast.decode_batch().
  • Moved the fallback into the native PyO3 binding, where the conversion error actually happens.
  • First try the normal Vec<u32> extraction.
  • Only if that hits OverflowError, retry by extracting signed integers and dropping IDs outside [0, 2^32 - 1].
  • Applied the same logic to both single decode and batch decode.

Why this shape

This is the narrowest place to fix the bug:

  • it catches the boundary conversion failure at the native entry point,
  • it avoids a Python-side pre-scan on every decode,
  • it keeps the normal path unchanged for valid inputs,
  • and it makes malformed decode input fail open instead of crashing the process.

Performance

The common path still uses the normal Vec<u32> extraction, so there is no extra pre-filtering pass for valid inputs.

I re-ran local decode microbenchmarks against the baseline wheel. The numbers stayed in the same range, and the key property is that the fallback only runs on the exceptional overflow path, not on the hot path.

Testing

Validated locally:

cargo test --manifest-path python/Cargo.toml decode_mixed_valid_and_unknown_ids -- --nocapture
maturin build --release -i python3.10

Smoke test on the built wheel:

fastokens.patch_transformers()
tok.decode([1, -1, 2, 2**32, 3])
tok.batch_decode([[1, -1, 2], [2**32, 3]])

zhiguo.qin and others added 3 commits August 10, 2026 19:08
…r-only

The native fallback only caught OverflowError and then re-extracted the ids as
Vec<i64>. That still aborted decode on inputs it was meant to tolerate:
- a float such as -inf/inf/nan (or any non-integer) fails Vec<u32> extraction
  with TypeError, which was re-raised;
- an int beyond i64 (e.g. 2**100) survived the OverflowError branch only to
  overflow again during the Vec<i64> re-extraction.

Broaden the fallback: on any rejection of the fast Vec<u32> extraction, iterate
the sequence element-wise, keep the elements that extract as an i64 in
[0, u32::MAX], and skip the rest. Floats, NaN, +/-inf, and >i64 ints are now
dropped like out-of-range ints instead of crashing the decode. The all-valid
fast path (one bulk Vec<u32> extraction) is unchanged, so there is no cost on
the common path.

Adds native tests (no transformers dependency) covering the float/inf/nan and
>i64 cases the previous fallback could not handle.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AlonKejzman

Copy link
Copy Markdown
Collaborator

Thank you for your contribution!

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@AlonKejzman
AlonKejzman merged commit 6ceb6a8 into crusoecloud:main Aug 10, 2026
19 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.

2 participants