{"record":{"id":"b5014bb1c395a08c","repo":"vllm-project/vllm","slug":"prompt-lookup-min-self-prompt-lookup-min-must-be","errorCode":null,"errorMessage":"prompt_lookup_min={self.prompt_lookup_min} must be <= prompt_lookup_max={self.prompt_lookup_max}","messagePattern":"prompt_lookup_min=(.+?) must be <= prompt_lookup_max=(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"vllm/config/speculative.py","lineNumber":826,"sourceCode":"                self.prompt_lookup_max = 5\n            elif self.prompt_lookup_min is None:\n                if self.prompt_lookup_max is None:\n                    raise ValueError(\n                        \"Either prompt_lookup_max or prompt_lookup_min must be \"\n                        \"provided when using the ngram method.\"\n                    )\n                self.prompt_lookup_min = self.prompt_lookup_max\n            elif self.prompt_lookup_max is None:\n                if self.prompt_lookup_min is None:\n                    raise ValueError(\n                        \"Either prompt_lookup_max or prompt_lookup_min must be \"\n                        \"provided when using the ngram method.\"\n                    )\n                self.prompt_lookup_max = self.prompt_lookup_min\n\n            # Validate values\n            if self.prompt_lookup_min > self.prompt_lookup_max:\n                raise ValueError(\n                    f\"prompt_lookup_min={self.prompt_lookup_min} must \"\n                    f\"be <= prompt_lookup_max={self.prompt_lookup_max}\"\n                )\n\n            # TODO: current we still need extract vocab_size from target model\n            # config, in future, we may try refactor it out, and set\n            # draft related config as None here.\n            self.draft_model_config = self.target_model_config\n            self.draft_parallel_config = self.target_parallel_config\n        elif self.method == \"suffix\":\n            self._validate_suffix_decoding()\n        elif self.method == \"custom_class\":\n            # Custom class proposer does not need a draft model.\n            # It will dynamically load the user-provided class at runtime.\n            logger.warning_once(\n                \"Using a custom class-based proposer backend. This is an \"\n                \"experimental feature and the proposer interface is subject to \"\n                \"breaking changes in future vLLM releases.\"","sourceCodeStart":808,"sourceCodeEnd":844,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/vllm/config/speculative.py#L808-L844","documentation":"Raised by SpeculativeConfig when using the 'ngram' speculative decoding method and prompt_lookup_min ends up strictly greater than prompt_lookup_max after the defaulting logic (unset max defaults to min, unset min defaults to max). The ngram worker uses both bounds to size its lookup window, so an inverted range is invalid. It is a plain ValueError thrown during engine/config construction, before any model loads.","triggerScenarios":"Passing speculative_config='{\"method\": \"ngram\", \"prompt_lookup_min\": 5, \"prompt_lookup_max\": 3}' (or the equivalent CLI flags --speculative-config / --ngram-prompt-lookup-max with a smaller max than min). Any ngram config where min > max after defaults are applied.","commonSituations":"Copying an ngram config example and tuning the two knobs independently; swapping min/max values by hand; setting a large prompt_lookup_min hoping to raise the window while leaving an old smaller max in the config string.","solutions":["Set prompt_lookup_max >= prompt_lookup_min (e.g. raise max or lower min) in the speculative_config dict/JSON","Omit prompt_lookup_min entirely so it defaults to prompt_lookup_max","Omit prompt_lookup_max so it defaults to prompt_lookup_min"],"exampleFix":"# before\nspeculative_config={\"method\": \"ngram\", \"prompt_lookup_min\": 10, \"prompt_lookup_max\": 4}\n# after\nspeculative_config={\"method\": \"ngram\", \"prompt_lookup_min\": 4, \"prompt_lookup_max\": 10}","handlingStrategy":"validation","validationCode":"def check_ngram_bounds(pl_min: int | None, pl_max: int | None) -> None:\n    if pl_min is not None and pl_max is not None and pl_min > pl_max:\n        raise ValueError(f\"prompt_lookup_min={pl_min} must be <= prompt_lookup_max={pl_max}\")\n\ncheck_ngram_bounds(cfg.get(\"prompt_lookup_min\"), cfg.get(\"prompt_lookup_max\"))\nspeculative_config = cfg","typeGuard":"def is_valid_ngram_pair(pl_min: int | None, pl_max: int | None) -> bool:\n    return pl_min is None or pl_max is None or pl_min <= pl_max","tryCatchPattern":null,"preventionTips":["Keep ngram lookup knobs in one place (a dataclass or single YAML block) so min/max cannot drift apart","Assert min <= max in your config loader before handing the dict to vLLM"],"tags":["speculative-decoding","ngram","config","validation"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}