vllm-project/vllm · error · ValueError
method='custom_class' requires 'model' to contain the custom
Error message
method='custom_class' requires 'model' to contain the custom proposer module path (e.g., 'my_module.MyProposer').
What it means
For method='custom_class', the draft proposer is user-supplied Python: the 'model' field must carry an importable 'module.ClassName' path. Unlike other methods there is nothing to auto-fill, so if model is None the config is rejected rather than silently loading nothing.
Source
Thrown at vllm/config/speculative.py:791
# DeepSeek DSpark can ship the weights inside the target checkpoint
if self.target_model_config is None:
raise ValueError("target_model_config must be present for dspark")
self.model = self.target_model_config.model
if not self.quantization:
self.quantization = self.target_model_config.quantization
elif self.method in ("ngram", "[ngram]"):
self.model = "ngram"
elif self.method == "ngram_gpu":
self.model = "ngram_gpu"
elif self.method == "suffix":
self.model = "suffix"
elif self.method == "extract_hidden_states":
self.model = "extract_hidden_states"
elif self.method == "custom_class":
# method was set explicitly, but model should already contain the
# custom module path. If not, this is a configuration error.
if self.model is None:
raise ValueError(
"method='custom_class' requires 'model' to contain the "
"custom proposer module path (e.g., 'my_module.MyProposer')."
)
else:
raise ValueError(
"num_speculative_tokens was provided but without speculative model."
)
if self.method in ("ngram", "[ngram]"):
self.method = "ngram"
if self.method in ("ngram", "ngram_gpu"):
# Set default values if not provided
if self.prompt_lookup_min is None and self.prompt_lookup_max is None:
# TODO(woosuk): Tune these values. They are arbitrarily chosen.
self.prompt_lookup_min = 5
self.prompt_lookup_max = 5
elif self.prompt_lookup_min is None:View on GitHub (pinned to c794754062)
Solutions
- Set model to the dotted path of your proposer class, e.g. model='my_plugin.proposers.MyProposer'
- Ensure the module is importable in the vLLM process (installed or on PYTHONPATH)
- Verify the class is a registered/compatible speculative proposer before launch
Example fix
# before SpeculativeConfig(method='custom_class', num_speculative_tokens=3) # after SpeculativeConfig(method='custom_class', num_speculative_tokens=3, model='my_plugin.proposers.MyProposer')
Defensive patterns
Strategy: validation
Validate before calling
import importlib
def proposer_path_ok(path: str | None) -> bool:
if not isinstance(path, str) or '.' not in path:
return False
mod, cls = path.rsplit('.', 1)
try:
return hasattr(importlib.import_module(mod), cls)
except ImportError:
return False Type guard
def is_custom_class_path(v: object) -> bool:
return isinstance(v, str) and '.' in v and v.rsplit('.', 1)[1].isidentifier() Try / catch
null
Prevention
- Always pair method='custom_class' with a module.Class model path
- Verify importability of the proposer module in the serving environment
When it happens
Trigger: SpeculativeConfig(method='custom_class', num_speculative_tokens=3) with no model; passing the class object in another field instead of the dotted path string; typo in the method name leaving model unset.
Common situations: Migrating from ngram/MTP configs and forgetting that custom_class has no default proposer; assuming model only names HF checkpoints.
Related errors
- target_model_config must be present for mtp
- target_model_config must be present for dspark
- num_speculative_tokens was provided but without speculative
- The model is not multimodal.
- rejection_sample_method='synthetic' requires exactly one of
AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14).
Data as JSON: /api/errors/8e0448823eee8314.
Report an issue: GitHub.