sgl-project/sglang · error · ValueError

op {op!r} has multiple backends usable on device {platform.d

Error message

op {op!r} has multiple backends usable on device {platform.device.value!r} ({[s.backend.value for s in eligible]}); pass backend=... to choose one

What it means

Raised when an op has multiple backends that are ALL eligible on the current device and the caller did not pass backend=. Because selection would be ambiguous, sglang refuses to pick and asks for an explicit choice. This is the documented disambiguation error from select_kernel.

Source

Thrown at python/sglang/kernels/selector.py:80

        for spec in specs:
            if spec.backend == backend:
                return spec
        raise KeyError(f"No '{backend.value}' backend registered for op {op!r}")

    if len(specs) == 1:
        return specs[0]

    # Multiple backends: hard-filter by device eligibility.
    platform = _platform()
    eligible = [s for s in specs if s.is_available(platform)]
    if len(eligible) == 1:
        return eligible[0]
    if not eligible:
        raise ValueError(
            f"op {op!r} has no backend usable on device {platform.device.value!r} "
            f"(registered: {[s.backend.value for s in specs]})"
        )
    raise ValueError(
        f"op {op!r} has multiple backends usable on device "
        f"{platform.device.value!r} ({[s.backend.value for s in eligible]}); "
        f"pass backend=... to choose one"
    )


@lru_cache(maxsize=None)
def _resolve(op: str, backend: Optional[KernelBackend]) -> Callable:
    return select_kernel(op, backend=backend).load()


def get_kernel(op: str, backend: Optional[KernelBackend] = None) -> Callable:
    """Resolve ``op`` to a callable kernel and cache it.

    This is what the public ``sglang.kernels.ops.*`` wrappers call. The first
    call resolves and imports the backend; later calls hit the cache.
    """
    return _resolve(op, backend)

View on GitHub (pinned to 0132848349)

Solutions

  1. Pass backend=Backend.X explicitly to select_kernel for this op.
  2. Expose a backend override in your config (env var / CLI flag) so users on multi-backend hosts can choose.
  3. If one backend should always win, register only it, or wrap resolution with your own priority ordering.

Example fix

# before
spec = select_kernel(op)

# after
from sglang.kernels import Backend
spec = select_kernel(op, backend=Backend.FLASHINFER)
Defensive patterns

Strategy: validation

Validate before calling

from sglang.kernels.registry import registry
from sglang.kernels.platform import _platform

p = _platform()
eligible = [s for s in registry.get(op, []) if s.is_available(p)]
if len(eligible) > 1:
    spec = select_kernel(op, backend=eligible[0].backend)  # or user-chosen
else:
    spec = select_kernel(op)

Try / catch

try:
    spec = select_kernel(op)
except ValueError as e:
    if 'multiple backends' in str(e):
        spec = select_kernel(op, backend=DEFAULT_BACKEND)
    else:
        raise

Prevention

When it happens

Trigger: select_kernel(op) where registry has >=2 specs (e.g. triton and flashinfer) and both is_available(platform) checks pass — typical in tests like test_multi_backend_requires_explicit_backend and on fully-provisioned GPU hosts.

Common situations: Benchmarking or portability code that calls the generic resolver on a machine with several backends installed; new ops that register a second backend without a priority mechanism.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/35176eac9eaf075f. Report an issue: GitHub.