microsoft/semantic-kernel · error · AssertionError

return not found in function signature

Error message

return not found in function signature

What it means

Raised by the @message_handler decorator when the decorated method has no return type annotation. The decorator inspects type_hints['return'] to determine which message types the handler produces, so a missing return annotation (even -> None) prevents routing of responses.

Source

Thrown at python/semantic_kernel/agents/runtime/core/routed_agent.py:135

        func: The function to be decorated.
        strict: If `True`, the handler will raise an exception if the message type or return type is not in the target
            types. If `False`, it will log a warning instead.
        match: A function that takes the message and the context as arguments and returns a boolean. This is used for
            secondary routing after the message type. For handlers addressing the same message type, the match function
            is applied in alphabetical order of the handlers and the first matching handler will be called while the
            rest are skipped. If `None`, the first handler in alphabetical order matching the same message type will
            be called.
    """

    def decorator(
        func: Callable[[AgentT, ReceivesT, MessageContext], Coroutine[Any, Any, ProducesT]],
    ) -> MessageHandler[AgentT, ReceivesT, ProducesT]:
        type_hints = get_type_hints(func)
        if "message" not in type_hints:
            raise AssertionError("message parameter not found in function signature")

        if "return" not in type_hints:
            raise AssertionError("return not found in function signature")

        # Get the type of the message parameter
        target_types = get_types(type_hints["message"])
        if target_types is None:
            raise AssertionError("Message type not found")

        return_types = get_types(type_hints["return"])

        if return_types is None:
            raise AssertionError("Return type not found")

        # Convert target_types to list and stash

        @wraps(func)
        async def wrapper(self: AgentT, message: ReceivesT, ctx: MessageContext) -> ProducesT:
            if type(message) not in target_types:
                if strict:
                    raise CantHandleException(f"Message type {type(message)} not in target types {target_types}")

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Add an explicit return annotation, e.g. -> None or -> ResponseMsg.
  2. For handlers that return nothing, annotate -> None explicitly.
  3. Ensure any names in string annotations are imported and resolvable by get_type_hints.
  4. If using from __future__ import annotations, confirm all referenced types are in scope.

Example fix

// before
@message_handler
async def handle(self, message: MyMsg, ctx: MessageContext): ...
// after
@message_handler
async def handle(self, message: MyMsg, ctx: MessageContext) -> None: ...
Defensive patterns

Strategy: validation

Validate before calling

from typing import get_type_hints

def handler_has_return_annotation(func) -> bool:
    return "return" in get_type_hints(func)

Type guard

from typing import get_type_hints, Callable

def handler_has_return(func: Callable) -> bool:
    try:
        return "return" in get_type_hints(func)
    except Exception:
        return False

Prevention

When it happens

Trigger: Decorating an async method without a -> annotation, or an annotation that get_type_hints cannot resolve.

Common situations: Omitting the return annotation on a fire-and-forget handler (must still write -> None); PEP 484 string annotations referencing unresolved names.

Related errors


AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13). Data as JSON: /api/errors/1fb50f088c8079c2. Report an issue: GitHub.