sgl-project/sglang · error · ValueError
Invalid transition for {request_id}: {old_state.value} -> {n
Error message
Invalid transition for {request_id}: {old_state.value} -> {new_state.value} What it means
Raised by RequestStateStore.transition when the requested state change is not in _VALID_TRANSITIONS for the current state — the request lifecycle state machine (e.g. PENDING -> DISPATCHED -> ENCODING -> TRANSFER_STAGED -> DECODING -> DONE) only permits specific edges. Any out-of-order or illegal edge (e.g. PENDING straight to DONE, DECODING back to ENCODING) triggers this.
Source
Thrown at python/sglang/multimodal_gen/runtime/disaggregation/request_state.py:116
denoiser_instance: int | None = None,
decoder_instance: int | None = None,
) -> RequestRecord:
with self._lock:
record = self._requests.get(request_id)
if record is None:
raise ValueError(f"Unknown request_id: {request_id}")
old_state = record.state
if new_state in _TERMINAL_STATES and new_state != RequestState.DONE:
# FAILED / TIMED_OUT: allowed from any active state
if old_state not in _ACTIVE_STATES:
raise ValueError(
f"Cannot transition {request_id} from terminal state "
f"{old_state.value} to {new_state.value}"
)
elif new_state not in _VALID_TRANSITIONS.get(old_state, set()):
raise ValueError(
f"Invalid transition for {request_id}: "
f"{old_state.value} -> {new_state.value}"
)
record.state = new_state
record.last_transition_time = time.monotonic()
if error is not None:
record.error = error
if encoder_instance is not None:
record.encoder_instance = encoder_instance
if denoiser_instance is not None:
record.denoiser_instance = denoiser_instance
if decoder_instance is not None:
record.decoder_instance = decoder_instance
logger.debug(
"Request %s: %s -> %s", request_id, old_state.value, new_state.value
)View on GitHub (pinned to 0132848349)
Solutions
- Inspect record.state before calling transition and skip/log if the edge is invalid for the current lifecycle point
- Fix the ordering: ensure handlers fire in lifecycle order (dispatch before encoding, staging before decode), e.g. by gating on state rather than arrival order
- If you added a legitimate new edge, add it to _VALID_TRANSITIONS in request_state.py (library change)
- Make handlers idempotent so duplicate/replayed events cannot push the state machine backwards
Example fix
# before
store.transition(request_id, RequestState.DECODING) # illegal edge -> ValueError
# after
VALID = _VALID_TRANSITIONS.get(record.state, set())
if RequestState.DECODING in VALID:
store.transition(request_id, RequestState.DECODING)
else:
logger.warning("ignoring DECODING for %s in state %s", request_id, record.state) Defensive patterns
Strategy: validation
Validate before calling
from sglang.multimodal_gen.runtime.disaggregation.request_state import _VALID_TRANSITIONS
record = store.get(request_id)
if record is None or new_state not in _VALID_TRANSITIONS.get(record.state, set()):
logger.warning("illegal transition %s -> %s for %s; ignoring",
record.state if record else None, new_state, request_id)
return
store.transition(request_id, new_state) Type guard
def transition_allowed(current: RequestState, target: RequestState) -> bool:
return target in _VALID_TRANSITIONS.get(current, set()) Try / catch
try:
store.transition(request_id, new_state)
except ValueError as e:
if "Invalid transition" in str(e):
logger.warning("out-of-order event for %s; current=%s", request_id, new_state)
return
raise Prevention
- Gate handlers on the current record state instead of frame arrival order
- Make event handling idempotent so replays cannot rewind the state machine
- When adding states or edges, update _VALID_TRANSITIONS and add state-machine unit tests
When it happens
Trigger: Calling transition(id, new_state) with an edge absent from _VALID_TRANSITIONS[old_state] — e.g. _dispatch_to_encoder firing after the request already moved to DECODING, or skipping a required intermediate state because a handler ran out of order.
Common situations: Reordered async handlers (transfer completion racing encoder dispatch), duplicated event frames processed at the wrong lifecycle point, adding a new state/handler without updating _VALID_TRANSITIONS, or resuming a request from a checkpoint at the wrong recorded state.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot transition {request_id} from terminal state {old_stat
- Duplicate request_id: {request_id}
- Unknown request_id: {request_id}
- Missing previous frame for delta payload
- num_instances must be >= 1, got {num_instances}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/3619ae338ee01555.
Report an issue: GitHub.