sgl-project/sglang · error · AttributeError

kv-canary: {type(obj).__name__} missing required method {met

Error message

kv-canary: {type(obj).__name__} missing required method {method_name!r}

What it means

kv-canary's wrap_method monkey-patches an existing method on an object; if the object lacks the named method entirely there is nothing to wrap, so it raises AttributeError with the class and method name.

Source

Thrown at python/sglang/srt/kv_canary/pool_patcher/utils.py:28

    obj: object,
    method_name: str,
    *,
    wrapper: Callable[..., Any],
) -> None:
    """Replace ``obj.method_name`` with a closure that delegates to ``wrapper``.

    ``wrapper(original, *args, **kwargs)`` receives the original bound method as its first arg and the
    call-site args/kwargs as the rest. It decides when (and whether) to call ``original`` and what to
    return. The patched callable is installed as a plain function; :func:`functools.wraps` preserves
    ``__name__`` / ``__doc__`` but the bound-method nature of the original is not retained.

    Raises:
        AttributeError: ``obj`` has no attribute ``method_name``.
        RuntimeError: ``obj.method_name`` has already been wrapped by ``wrap_method`` (idempotency
            guard — re-wrapping silently would stack two transforms and corrupt return values).
    """
    if not hasattr(obj, method_name):
        raise AttributeError(
            f"kv-canary: {type(obj).__name__} missing required method {method_name!r}"
        )
    original = getattr(obj, method_name)
    if getattr(original, _WRAPPED_MARKER_ATTR, None) is not None:
        raise RuntimeError(
            f"kv-canary: {type(obj).__name__}.{method_name} already wrapped by kv-canary"
        )

    @functools.wraps(original)
    def patched(*args: Any, **kwargs: Any) -> Any:
        return wrapper(original, *args, **kwargs)

    setattr(patched, _WRAPPED_MARKER_ATTR, method_name)
    setattr(obj, method_name, patched)

View on GitHub (pinned to 0132848349)

Solutions

  1. Check hasattr(obj, method_name) before wrapping and pass the correct object that actually defines the method
  2. Update kv-canary to the new method name if SGLang renamed it
  3. Verify you are passing the instance (or class) that owns the method, not an unrelated wrapper

Example fix

// before
wrap_method(attn_backend, 'forward')
// after
if hasattr(attn_backend, 'forward'):
    wrap_method(attn_backend, 'forward')
else:
    wrap_method(attn_backend.model, 'forward')
Defensive patterns

Strategy: type-guard

Validate before calling

if not hasattr(obj, method_name):
    raise AttributeError(f'{type(obj).__name__} has no {method_name}; wrong object?')
wrap_method(obj, method_name, wrapper)

Type guard

def has_method(obj: object, name: str) -> bool:
    return callable(getattr(obj, name, None))

Try / catch

try:
    wrap_method(obj, method_name, wrapper)
except AttributeError as e:
    logger.error('cannot patch: %s', e)

Prevention

When it happens

Trigger: Calling wrap_method(model, 'forward') on an object whose class has no forward, or wrap_method(buf_info_obj, 'some_method') where the attribute was renamed or removed; also patch_buf_info_method / _patch_model_forward against an unexpected object type.

Common situations: Internal SGLang API changed the method name (e.g. forward refactor, BufferInfo method rename) and kv-canary was not updated; passing the wrong object (module vs instance, wrong wrapper class) to the patcher.

Related errors


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