{"record":{"id":"8b1a41be6c564a9e","repo":"vllm-project/vllm","slug":"synthetic-acceptance-length-must-be-in-1-n-1","errorCode":null,"errorMessage":"synthetic_acceptance_length must be in [1, {n + 1}], got {length}.","messagePattern":"synthetic_acceptance_length must be in \\[1, (.+?)\\], got (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"vllm/config/speculative.py","lineNumber":285,"sourceCode":"            )\n        if rates is not None:\n            if len(rates) != n:\n                raise ValueError(\n                    f\"synthetic_acceptance_rates must have length {n}, got {rates}.\"\n                )\n            if not all(0.0 <= r <= 1.0 for r in rates):\n                raise ValueError(\n                    f\"synthetic_acceptance_rates entries must be in [0, 1], \"\n                    f\"got {rates}.\"\n                )\n            if any(rates[i] > rates[i - 1] for i in range(1, n)):\n                raise ValueError(\n                    f\"synthetic_acceptance_rates must be non-increasing, got {rates}.\"\n                )\n            return list(rates)\n        assert length is not None\n        if not 1.0 <= length <= float(n + 1):\n            raise ValueError(\n                f\"synthetic_acceptance_length must be in [1, {n + 1}], got {length}.\"\n            )\n        return SpeculativeConfig._acceptance_length_to_rates(length, n)\n\n    draft_sample_method: DraftSampleMethod = \"greedy\"\n    \"\"\"How the draft model samples tokens. 'greedy' always picks the argmax\n    token, and the draft probabilities are treated as one-hot during rejection\n    sampling. 'probabilistic' samples stochastically from the draft\n    distribution and uses the full draft logits for the probability ratio test\n    during rejection sampling. This comes at the cost of additional GPU memory\n    usage.\"\"\"\n\n    dspark_draft_topk: int | None = Field(default=None, ge=1)\n    \"\"\"For Qwen3 DSpark drafting, evaluate the Markov projection only for the\n    top-k base-logit candidates. Requires draft tensor parallel size 1.\"\"\"\n\n    def compute_hash(self) -> str:\n        \"\"\"","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/vllm/config/speculative.py#L267-L303","documentation":"When synthetic_acceptance_length is used, it must lie in [1, n+1] where n is the speculative depth: the mean accepted length is at least 1 (the bonus/verified token) and at most the full draft chain plus one. Values outside mean the requested profile is impossible for this num_speculative_tokens.","triggerScenarios":"synthetic_acceptance_length=6 with num_speculative_tokens=3 (max is 4); length 0.5 (< 1); reusing a length tuned for a deeper draft config.","commonSituations":"Changing speculative depth without re-checking length bounds; interpreting length as accepted draft tokens (max n) instead of n+1; benchmark sweeps crossing depth boundaries.","solutions":["Scale the length to the current depth: 1 <= length <= num_speculative_tokens + 1","Or increase num_speculative_tokens so the chain covers the desired length","Use synthetic_acceptance_rates if you need control beyond what a single scalar can express"],"exampleFix":"# before\nnum_speculative_tokens=3, synthetic_acceptance_length=6.0\n\n# after\nnum_speculative_tokens=5, synthetic_acceptance_length=6.0","handlingStrategy":"validation","validationCode":"def length_ok(n: int, length: float) -> bool:\n    return 1.0 <= length <= float(n + 1)","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Scale acceptance length when changing speculative depth","Remember the upper bound is n+1, not n"],"tags":["speculative-decoding","config","validation","math"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}