sgl-project/sglang · error · AttributeError

{name}

Error message

{name}

What it means

The breakable CUDA graph runner wraps a transformer and forwards unknown attribute lookups to it via __getattr__. It deliberately reads self.__dict__['transformer'] to avoid recursing through __getattr__; if 'transformer' is not yet assigned — before/during __init__ or after a failed one — the KeyError is re-raised as AttributeError(name) for the requested name.

Source

Thrown at python/sglang/multimodal_gen/runtime/breakable_cuda_graph/runner.py:253

        self.entries: dict[tuple, _CaptureEntry] = {}
        # Signatures we have given up capturing (capture raised); run eager.
        self._blocked: set[tuple] = set()
        self._disabled_reason: str | None = None
        self.max_entries = max(0, _env_int("SGLANG_DIFFUSION_BCG_MAX_ENTRIES", 32))
        # LTX-2 dual-tower blocks carry 6 attention break points each
        # (video/audio self, video/audio prompt-cross, a2v, v2a), so 48 blocks
        # capture ~289 segments; keep headroom above that.
        self.max_segments = max(0, _env_int("SGLANG_DIFFUSION_BCG_MAX_SEGMENTS", 512))

    def __getattr__(self, name: str) -> Any:
        # Only reached for attributes the runner itself does not define; proxy
        # them to the wrapped transformer so callers can treat the runner as a
        # transparent stand-in. Use __dict__ to avoid recursing through
        # __getattr__ before ``transformer`` is assigned in __init__.
        try:
            transformer = self.__dict__["transformer"]
        except KeyError as e:  # pragma: no cover - during/ before __init__
            raise AttributeError(name) from e
        return getattr(transformer, name)

    # ------------------------------------------------------------------ #
    # Public capture / replay API
    # ------------------------------------------------------------------ #
    @torch.no_grad()
    def capture(self, **kwargs) -> bool:
        """Capture a graph for ``kwargs``'s signature if not already captured.

        Idempotent: returns ``True`` when a graph is available for the
        signature afterwards (already captured or newly captured), ``False``
        when capture is disabled/blocked or failed (the caller then runs eager).
        """
        if self._disabled_reason is not None:
            return False
        key = self._signature(kwargs)
        if key in self._blocked:
            return False

View on GitHub (pinned to 0132848349)

Solutions

  1. Check the traceback for an earlier failure — if __init__ crashed, fix that so 'transformer' is always assigned.
  2. Move attribute access out of base-class __init__ or defer it until after super().__init__() completes.
  3. If the attribute lives on the model, access it via runner.transformer.<attr> explicitly once initialized.

Example fix

// before
class MyRunner(BreakableCudaGraphRunner):
    def __init__(self):
        self.debug_flag = self.enable_debug  # hits __getattr__ pre-init
        super().__init__(...)
// after
class MyRunner(BreakableCudaGraphRunner):
    def __init__(self):
        super().__init__(...)
        self.debug_flag = self.enable_debug
Defensive patterns

Strategy: validation

Validate before calling

runner = BreakableCudaGraphRunner(...)
attr = getattr(runner, "some_attr", None)
if attr is None and "transformer" in runner.__dict__:
    attr = getattr(runner.transformer, "some_attr")

Type guard

def runner_ready(runner) -> bool:
    return "transformer" in runner.__dict__

Try / catch

try:
    val = runner.some_attr
except AttributeError:
    if "transformer" not in runner.__dict__:
        logger.error("runner not initialized; original __init__ likely failed")
    raise

Prevention

When it happens

Trigger: Accessing any attribute that exists on neither the runner nor (once initialized) the wrapped transformer, or any attribute access before __init__ assigned self.transformer — e.g. from a base-class constructor, a __init__ exception path, or unpickling that bypasses __init__.

Common situations: A crash inside runner __init__ followed by cleanup/logging code touching runner attributes; subclass overrides running before super().__init__(); copy/pickle or debuggers touching a partially constructed object; typos in attribute names that were expected on the wrapped transformer.

Related errors


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