sgl-project/sglang · error · RuntimeError

Ideogram4DenoisingStage applies its custom scheduler step

Error message

Ideogram4DenoisingStage applies its custom scheduler step

What it means

Ideogram4DenoisingStage ships its own custom denoising step implementation, so the stock scheduler API step() is intentionally disabled. Calling step() on this stage raises immediately — it exists only to satisfy the scheduler interface and signal misuse. The real step logic is applied inside the stage's forward/_denoise_* methods.

Source

Thrown at python/sglang/multimodal_gen/runtime/pipelines_core/stages/model_specific_stages/ideogram.py:116

        self._begin_index = None

    def set_begin_index(self, begin_index: int) -> None:
        self._begin_index = begin_index

    def set_timesteps(self, num_inference_steps: int, device=None) -> None:
        self.timesteps = torch.arange(
            num_inference_steps - 1,
            -1,
            -1,
            dtype=torch.float32,
            device=device or get_local_torch_device(),
        )

    def scale_model_input(self, sample: torch.Tensor, timestep=None) -> torch.Tensor:
        return sample

    def step(self, model_output, timestep, sample, return_dict=False, **kwargs):
        raise RuntimeError("Ideogram4DenoisingStage applies its custom scheduler step")


class Ideogram4TextEncodingStage(TextEncodingStage):
    deduplicated_extra_tensor_tree_output_keys = ("ideogram4",)

    def __init__(self, text_encoder, tokenizer) -> None:
        super().__init__([text_encoder], [tokenizer])

    def _tokenize(self, prompt: str, max_text_tokens: int):
        messages = [{"role": "user", "content": [{"type": "text", "text": prompt}]}]
        text = self.tokenizers[0].apply_chat_template(
            messages, add_generation_prompt=True, tokenize=False
        )
        encoded = self.tokenizers[0](
            text, return_tensors="pt", add_special_tokens=False
        )
        token_ids = encoded["input_ids"][0]
        num_text_tokens = int(token_ids.shape[0])

View on GitHub (pinned to 0132848349)

Solutions

  1. Do not call step() on Ideogram4DenoisingStage; let its forward()/custom denoise methods drive sampling
  2. Refactor shared sampling utilities to dispatch on stage type or use the stage's documented denoising entry point
  3. If you need custom stepping, implement it in the stage's _denoise_* hooks instead of calling step()

Example fix

# before
for t in timesteps:
    noise = model(x, t)
    x = ideogram_stage.step(noise, t, x).prev_sample

# after
# delegate to the stage's own denoising loop
x = ideogram_stage.forward(batch, server_args)
Defensive patterns

Strategy: type-guard

Validate before calling

from sglang.multimodal_gen.runtime.pipelines_core.stages.model_specific_stages.ideogram import Ideogram4DenoisingStage
if isinstance(stage, Ideogram4DenoisingStage):
    out = stage.forward(batch, server_args)  # custom loop
else:
    x = stage.step(noise, t, x).prev_sample

Type guard

def uses_custom_step(stage) -> bool:
    return isinstance(stage, Ideogram4DenoisingStage)

Try / catch

try:
    x = stage.step(noise, t, x)
except RuntimeError as e:
    if "custom scheduler step" in str(e):
        x = stage.forward(batch, server_args)
    else:
        raise

Prevention

When it happens

Trigger: Any code path that treats the stage like a standard diffusers SchedulerMixin and calls .step(model_output, timestep, sample), e.g. generic denoising-loop boilerplate reused across models, or third-party code iterating pipelines via the scheduler interface.

Common situations: Porting a generic diffusion sampling loop to Ideogram4D; a shared utility calling scheduler.step uniformly over all stages; version upgrade where the stage now subclasses a scheduler-like interface it previously did not.

Related errors


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