{"record":{"id":"14ba3f4f6188e8e2","repo":"vllm-project/vllm","slug":"synthetic-acceptance-rates-must-have-length-n-g","errorCode":null,"errorMessage":"synthetic_acceptance_rates must have length {n}, got {rates}.","messagePattern":"synthetic_acceptance_rates must have length (.+?), got (.+?)\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"vllm/config/speculative.py","lineNumber":270,"sourceCode":"            [1.0] * num_full + [num_drafts - num_full] + [0.0] * (n - num_full - 1)\n        )[:n]\n\n    @staticmethod\n    def _resolve_synthetic_acceptance_rates(\n        n: int,\n        rates: list[float] | None,\n        length: float | None,\n    ) -> list[float]:\n        \"\"\"Return per-position unconditional acceptance rates from exactly one\n        of `rates` or `length` (validates range, length, and monotonicity).\"\"\"\n        if (rates is None) == (length is None):\n            raise ValueError(\n                \"rejection_sample_method='synthetic' requires exactly one of \"\n                \"synthetic_acceptance_rates or synthetic_acceptance_length.\"\n            )\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)","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/vllm/config/speculative.py#L252-L288","documentation":"When explicit synthetic_acceptance_rates are given, the list must contain exactly n entries — one per speculative position (n = number of speculative tokens/depth). The rate at index i is the unconditional acceptance probability at position i, so a shorter or longer list cannot be mapped onto the draft chain.","triggerScenarios":"synthetic_acceptance_rates=[0.9] with num_speculative_tokens=3; reusing a rates profile tuned for a different speculative depth without resizing; off-by-one lists built from measurements of accepted length rather than per-position rates.","commonSituations":"Changing --num-speculative-tokens without regenerating the rates profile; copying benchmark profiles between models with different draft depths.","solutions":["Regenerate the rates list so len(rates) == num_speculative_tokens","Or switch to synthetic_acceptance_length, which is depth-independent and auto-converted","Derive rates programmatically: [min(1.0, L/(i+1)) for i in range(n)] from measured mean length L"],"exampleFix":"# before\nnum_speculative_tokens=3, synthetic_acceptance_rates=[0.9, 0.8]\n\n# after\nnum_speculative_tokens=3, synthetic_acceptance_rates=[0.9, 0.8, 0.7]","handlingStrategy":"validation","validationCode":"def rates_len_ok(n: int, rates: list[float]) -> bool:\n    return len(rates) == n","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Regenerate rate profiles whenever num_speculative_tokens changes","Generate rates from length: [min(1.0, L/(i+1)) for i in range(n)]"],"tags":["speculative-decoding","config","validation"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}