sgl-project/sglang · error · ValueError

control signal kind {item.kind!r} does not match queue kind

Error message

control signal kind {item.kind!r} does not match queue kind {kind!r}

What it means

A control-signal queue is typed to one signal kind; when push() expands a payload into signals, any ControlSignal whose kind differs from the queue's kind is rejected. This keeps per-kind queues homogeneous so consumers can assume the kind.

Source

Thrown at python/sglang/multimodal_gen/runtime/realtime/control_signals.py:292

    def _iter_signals(
        self,
        kind: str,
        payload: Any,
        *,
        event_id: int | None,
        timestamp_ms: int | None,
        expand_payload: bool,
    ):
        items = (
            payload
            if self._should_expand_payload(payload, expand_payload)
            else (payload,)
        )
        for item in items:
            if isinstance(item, ControlSignal):
                if item.kind != kind:
                    raise ValueError(
                        "control signal kind "
                        f"{item.kind!r} does not match queue kind {kind!r}"
                    )
                yield item
            else:
                yield ControlSignal(
                    kind=kind,
                    payload=item,
                    timestamp_ms=timestamp_ms,
                    seq_id=event_id,
                )

    @staticmethod
    def _should_expand_payload(payload: Any, expand_payload: bool) -> bool:
        return (
            expand_payload
            and isinstance(payload, Sequence)
            and not isinstance(payload, (str, bytes, bytearray))

View on GitHub (pinned to 0132848349)

Solutions

  1. Inspect the expanded items: ensure the payload only expands into signals of the queue's kind, or split the payload per kind and push to the matching queues.
  2. If a mixed-kind queue is intended, change the queue construction/typing to accept the union of kinds instead of pushing mismatched signals.
  3. Fix the kind string on the producer side (typo/case difference like 'input_audio' vs 'InputAudio').

Example fix

// before
queue = ControlSignalQueue(kind=ControlSignalKind.INTERRUPT)
queue.push(state_payload)  # expands into a 'commit' signal -> ValueError
// after
for signal in expand(state_payload):
    queues[signal.kind].push(signal)
Defensive patterns

Strategy: validation

Validate before calling

for sig in expand_signals(payload):
    assert sig.kind == queue.kind, f'route {sig.kind} to its own queue'

Type guard

def matches_queue_kind(signal, queue) -> bool:
    return signal.kind == queue.kind

Try / catch

try:
    queue.push(payload)
except ValueError as e:
    if 'does not match queue kind' in str(e):
        route_signals_individually(payload)

Prevention

When it happens

Trigger: Calling queue.push(payload, expand_payload=True) (or plain push of a ControlSignal) where the expanded/inserted ControlSignal.kind != the kind the queue was constructed with.

Common situations: Payload expansion (e.g. a state payload that fans out into multiple signal kinds) producing a signal of a different kind; refactoring kinds or adding a new kind and routing it to the wrong queue; reusing a queue across kinds.

Understand the failure class

Background: Invalid argument type errors: "must be of type string", "expected X, got Y", and ERR_INVALID_ARG_TYPE explained — this error's family across 15 libraries.

Related errors


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