{"record":{"id":"cad82f4e0d957a07","repo":"sgl-project/sglang","slug":"stop-stop-strs-r-is-unavailable-when-skip-tokeni","errorCode":null,"errorMessage":"stop={stop_strs!r} is unavailable when skip_tokenizer_init=True (requires tokenizer to decode tokens to text for matching).","messagePattern":"stop=(.+?) is unavailable when skip_tokenizer_init=True \\(requires tokenizer to decode tokens to text for matching\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/sampling/sampling_params.py","lineNumber":324,"sourceCode":"\n    return total\n\n\ndef raise_if_tokenizer_required(\n    tokenizer, stop_strs, stop_regex_strs, min_new_tokens=0\n):\n    \"\"\"Raise ValueError if tokenizer-dependent features are used without a tokenizer.\n\n    String-based stop conditions (stop_strs, stop_regex_strs) require tokenizer.decode()\n    to convert output token IDs to text for matching. min_new_tokens requires the\n    tokenizer's eos_token_id to penalize. When skip_tokenizer_init=True, these cannot\n    be used.\n    \"\"\"\n    if tokenizer is not None:\n        return\n\n    if stop_strs:\n        raise ValueError(\n            f\"stop={stop_strs!r} is unavailable when skip_tokenizer_init=True \"\n            \"(requires tokenizer to decode tokens to text for matching).\"\n        )\n    if stop_regex_strs:\n        raise ValueError(\n            f\"stop_regex={stop_regex_strs!r} is unavailable when skip_tokenizer_init=True \"\n            \"(requires tokenizer to decode tokens to text for matching).\"\n        )\n    if min_new_tokens > 0:\n        raise ValueError(\n            f\"min_new_tokens={min_new_tokens} is unavailable when skip_tokenizer_init=True \"\n            \"(requires tokenizer for eos_token_id).\"\n        )\n","sourceCodeStart":306,"sourceCodeEnd":338,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/sampling/sampling_params.py#L306-L338","documentation":"When the server is started with --skip-tokenizer-init (tokenizer is None), stop strings cannot be matched because matching requires decoding generated tokens to text. normalize() calls raise_if_tokenizer_required, which rejects stop_strs in that mode.","triggerScenarios":"Server launched with --skip-tokenizer-init (input_ids passed directly) and the request includes SamplingParams(stop=[\"<some text>\"]) or stop_token_ids containing strings.","commonSituations":"Benchmarking/prefill-token pipelines that skip tokenization but reuse a client template with string stop conditions; migrating a workload to token-id-only serving without stripping text-based stop params.","solutions":["Remove stop strings; use stop_token_ids (integer ids) instead.","Or restart the server without --skip-tokenizer-init if text-level stopping is required."],"exampleFix":"# before\nSamplingParams(stop=[\"</answer>\"])  # with --skip-tokenizer-init\n# after\nSamplingParams(stop_token_ids=[tokenizer.convert_tokens_to_ids(\"</answer>\")])","handlingStrategy":"type-guard","validationCode":"if skip_tokenizer_init and params.get('stop'):\n    params['stop_token_ids'] = [tid for tid in to_ids(params.pop('stop'))]\n    params['stop'] = None","typeGuard":"def stop_ok_without_tokenizer(params: SamplingParams) -> bool:\n    return not params.stop_strs","tryCatchPattern":null,"preventionTips":["Keep two request templates: one for tokenizer-free endpoints (ids only), one for normal endpoints.","Convert string stops to token ids at client build time against the served tokenizer."],"tags":["skip-tokenizer-init","stop-strings","sampling-params","sglang"],"backgroundTag":"feature-requires-tokenizer","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}