vllm-project/vllm · error · ValueError

rejection_sample_method='synthetic' requires exactly one of

Error message

rejection_sample_method='synthetic' requires exactly one of synthetic_acceptance_rates or synthetic_acceptance_length.

What it means

SpeculativeConfig._resolve_synthetic_acceptance_rates requires exactly one of synthetic_acceptance_rates (explicit per-position rates) or synthetic_acceptance_length (mean accepted length, converted to rates). The check (rates is None) == (length is None) fires when both are given or neither is — the synthetic rejection-sample profile is ambiguous.

Source

Thrown at vllm/config/speculative.py:264

    def _acceptance_length_to_rates(length: float, n: int) -> list[float]:
        """Mean acceptance length to unconditional per-position rates, using
        the minimum-variance schedule."""
        num_drafts = length - 1  # expected number of accepted draft tokens
        num_full = int(num_drafts)
        return (
            [1.0] * num_full + [num_drafts - num_full] + [0.0] * (n - num_full - 1)
        )[:n]

    @staticmethod
    def _resolve_synthetic_acceptance_rates(
        n: int,
        rates: list[float] | None,
        length: float | None,
    ) -> list[float]:
        """Return per-position unconditional acceptance rates from exactly one
        of `rates` or `length` (validates range, length, and monotonicity)."""
        if (rates is None) == (length is None):
            raise ValueError(
                "rejection_sample_method='synthetic' requires exactly one of "
                "synthetic_acceptance_rates or synthetic_acceptance_length."
            )
        if rates is not None:
            if len(rates) != n:
                raise ValueError(
                    f"synthetic_acceptance_rates must have length {n}, got {rates}."
                )
            if not all(0.0 <= r <= 1.0 for r in rates):
                raise ValueError(
                    f"synthetic_acceptance_rates entries must be in [0, 1], "
                    f"got {rates}."
                )
            if any(rates[i] > rates[i - 1] for i in range(1, n)):
                raise ValueError(
                    f"synthetic_acceptance_rates must be non-increasing, got {rates}."
                )
            return list(rates)

View on GitHub (pinned to c794754062)

Solutions

  1. Provide exactly one of synthetic_acceptance_rates or synthetic_acceptance_length
  2. For a target mean accepted length use synthetic_acceptance_length (simpler); for precise per-position control use rates
  3. Strip the unused key from YAML/JSON overlays that may inject it

Example fix

# before
SpeculativeConfig(rejection_sample_method='synthetic', synthetic_acceptance_rates=[0.9, 0.8], synthetic_acceptance_length=2.0)

# after
SpeculativeConfig(rejection_sample_method='synthetic', synthetic_acceptance_length=2.0)
Defensive patterns

Strategy: validation

Validate before calling

def exactly_one(rates, length) -> bool:
    return (rates is None) != (length is None)

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: SpeculativeConfig(rejection_sample_method='synthetic') with neither rates nor length; supplying both synthetic_acceptance_rates=[...] and synthetic_acceptance_length=2.5; leftover defaults from config templates filling both fields.

Common situations: Config templating that sets 'sensible defaults' for every field; upgrading from an API that accepted either implicitly; merging YAML overlays that each contribute one of the two keys.

Related errors


AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14). Data as JSON: /api/errors/ba716e61c162e684. Report an issue: GitHub.