{"record":{"id":"9465118000a40fce","repo":"vllm-project/vllm","slug":"synthetic-acceptance-rates-synthetic-acceptance","errorCode":null,"errorMessage":"synthetic_acceptance_rates / synthetic_acceptance_length are only valid with rejection_sample_method='synthetic'.","messagePattern":"synthetic_acceptance_rates / synthetic_acceptance_length are only valid with rejection_sample_method='synthetic'\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"vllm/config/speculative.py","lineNumber":1377,"sourceCode":"        if self.num_speculative_tokens <= 0:\n            raise ValueError(\n                \"Expected num_speculative_tokens to be greater \"\n                f\"than zero ({self.num_speculative_tokens}).\"\n            )\n\n        if self.rejection_sample_method == \"synthetic\":\n            # Consolidate to per-position rates\n            self.synthetic_acceptance_rates = self._resolve_synthetic_acceptance_rates(\n                self.num_speculative_tokens,\n                self.synthetic_acceptance_rates,\n                self.synthetic_acceptance_length,\n            )\n            self.synthetic_acceptance_length = None\n        elif (\n            self.synthetic_acceptance_rates is not None\n            or self.synthetic_acceptance_length is not None\n        ):\n            raise ValueError(\n                \"synthetic_acceptance_rates / synthetic_acceptance_length \"\n                \"are only valid with rejection_sample_method='synthetic'.\"\n            )\n\n        if self.draft_model_config:\n            self.draft_model_config.verify_with_parallel_config(\n                self.draft_parallel_config\n            )\n\n        if self.use_heterogeneous_vocab and not self.uses_draft_model():\n            raise ValueError(\n                \"use_heterogeneous_vocab only works with method='draft_model'\"\n            )\n\n        if self.use_heterogeneous_vocab and self.draft_sample_method != \"greedy\":\n            raise ValueError(\n                \"use_heterogeneous_vocab currently only supports greedy draft \"\n                \"sampling. Set draft_sample_method='greedy' (the default) or \"","sourceCodeStart":1359,"sourceCodeEnd":1395,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/vllm/config/speculative.py#L1359-L1395","documentation":"vLLM's SpeculativeConfig rejects the synthetic acceptance tuning knobs (synthetic_acceptance_rates / synthetic_acceptance_length) unless rejection_sample_method is set to 'synthetic'. These parameters model a synthetic acceptance distribution instead of using a real draft model, so they are meaningless (and silently misleading) under other rejection-sampling methods. The check runs in the post-init validator of SpeculativeConfig, so it fires at config construction time before any engine startup.","triggerScenarios":"Creating EngineArgs/VllmConfig (e.g. LLM(model=...), vllm serve) with speculative_config containing num_speculative_tokens plus synthetic_acceptance_rates or synthetic_acceptance_length, while rejection_sample_method is left at its default or set to a non-'synthetic' value (e.g. 'rejection_sample').","commonSituations":"Copy-pasting a benchmark config that used synthetic drafting into a setup running a real draft model; upgrading vLLM where the synthetic acceptance API was introduced and forgetting the companion method flag; setting synthetic_acceptance_length for ngram/draft_model speculative decoding expecting it to act as a target rate.","solutions":["Set rejection_sample_method='synthetic' in the speculative config (e.g. --speculative-config '{\"method\":\"ngram\",...}' style JSON or CLI flag) so the knobs are honored","Remove synthetic_acceptance_rates and synthetic_acceptance_length from the config if you intend to use a real draft model or another rejection sampling method","If you only want a target acceptance length, keep exactly one knob and the 'synthetic' method; the config resolves rates from the length automatically"],"exampleFix":"# before\nspeculative_config = {\n    \"method\": \"ngram\",\n    \"num_speculative_tokens\": 5,\n    \"synthetic_acceptance_length\": 3.0,\n}\n# after\nspeculative_config = {\n    \"method\": \"ngram\",\n    \"rejection_sample_method\": \"synthetic\",\n    \"num_speculative_tokens\": 5,\n    \"synthetic_acceptance_length\": 3.0,\n}","handlingStrategy":"validation","validationCode":"from vllm.config.speculative import SpeculativeConfig\nspec = {\"method\": \"ngram\", \"num_speculative_tokens\": 5,\n        \"synthetic_acceptance_length\": 3.0}\nhas_syn = any(spec.get(k) is not None for k in\n             (\"synthetic_acceptance_rates\", \"synthetic_acceptance_length\"))\nassert not has_syn or spec.get(\"rejection_sample_method\") == \"synthetic\", \\\n    \"synthetic_acceptance_* requires rejection_sample_method='synthetic'\"","typeGuard":"def is_valid_synthetic_spec(spec: dict) -> bool:\n    uses_syn = any(spec.get(k) is not None\n                   for k in (\"synthetic_acceptance_rates\",\n                             \"synthetic_acceptance_length\"))\n    return not uses_syn or spec.get(\"rejection_sample_method\") == \"synthetic\"","tryCatchPattern":null,"preventionTips":["Keep synthetic-acceptance knobs in the same config template as rejection_sample_method='synthetic' so they are never separated","Validate speculative-config dicts with a helper before passing to LLM()/serve","When switching speculative methods, strip method-specific fields instead of only changing 'method'"],"tags":["speculative-decoding","config","validation"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}