microsoft/semantic-kernel · error · ValueError

Return type {type(return_value)} is not None.

Error message

Return type {type(return_value)} is not None.

What it means

Raised at runtime by the @event wrapper. Event handlers must return None (events are fire-and-forget). The wrapper awaits the function and, if the return value is not None, raises ValueError in strict mode (default True) or logs a warning otherwise. This enforces the event contract that events cannot produce responses.

Source

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

        return_types = get_types(type_hints["return"])

        if return_types is None:
            raise AssertionError("Return type not found. Please use `None` as the type hint of the return type.")

        # Convert target_types to list and stash

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

            return_value = await func(self, message, ctx)  # type: ignore

            if return_value is not None:
                if strict:
                    raise ValueError(f"Return type {type(return_value)} is not None.")
                logger.warning(f"Return type {type(return_value)} is not None. It will be ignored.")

            return

        wrapper_handler = cast(MessageHandler[AgentT, ReceivesT, None], wrapper)
        wrapper_handler.target_types = list(target_types)
        wrapper_handler.produces_types = list(return_types)
        wrapper_handler.is_message_handler = True
        # Wrap the match function with a check on the is_rpc flag.
        wrapper_handler.router = lambda _message, _ctx: (not _ctx.is_rpc) and (match(_message, _ctx) if match else True)

        return wrapper_handler

    if func is None and not callable(func):
        return decorator
    if callable(func):
        return decorator(func)
    raise ValueError("Invalid arguments")

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Ensure the event handler returns nothing (end without return, or use a bare 'return' / 'return None').
  2. If a value must come back, switch to @rpc.
  3. Pass strict=False to downgrade to a warning if a stray return is acceptable.

Example fix

// before
@event
async def on_event(self, message: E, ctx: MessageContext) -> None:
    return self.compute(message)  # non-None -> ValueError

// after
@event
async def on_event(self, message: E, ctx: MessageContext) -> None:
    self.compute(message)
Defensive patterns

Strategy: validation

Validate before calling

import asyncio

def returns_none_when_awaited(handler, *args) -> bool:
    return asyncio.get_event_loop().run_until_complete(handler(*args)) is None

Try / catch

try:
    await runtime.send_message(msg, agent_id)
except ValueError as e:
    if 'is not None' in str(e):
        logger.error('Event handler returned a value: %s', e)

Prevention

When it happens

Trigger: An @event handler returns a non-None value: an explicit return of a computed result/message, or an implicit return of an expression. Strict mode (default) turns it into a ValueError.

Common situations: Forgetting to drop a return statement after refactoring an RPC handler into an event handler; returning a status/ack object; an accidental trailing expression.

Related errors


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