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
- 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.
- If a mixed-kind queue is intended, change the queue construction/typing to accept the union of kinds instead of pushing mismatched signals.
- 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
- Keep a dict of queues keyed by kind and always push expanded signals to queues[sig.kind].
- Never push raw expandable payloads into a single-kind queue unless expansion is kind-stable.
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
- Unsupported type {type(data)}
- All tensors must have the same data type
- camera_actions event payload must be list[list[str]]
- composite_input input_types must contain non-empty strings
- Expected BasicTransformerBlock, got {type(transformer).__nam
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/d27c8e5fe5e4309a.
Report an issue: GitHub.