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
- Ensure the event handler returns nothing (end without return, or use a bare 'return' / 'return None').
- If a value must come back, switch to @rpc.
- 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
- Event handlers must return None; add a test asserting the awaited result is None.
- When converting an RPC handler to an event handler, strip every return statement.
- Keep strict=True in CI to catch stray returns early.
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
- Message type not found. Please provide a type hint for the m
- Agent Failure - Run terminated: {run.Status} [{run.Id}]: {ru
- Agent Failure - Run not created for thread: ${threadId}
- Invalid AgentId key: '{key}'. Must only contain ASCII charac
- Invalid AgentId type: '{type}'. Must be alphanumeric (a-z, 0
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/9bb241e5d3a5e202.
Report an issue: GitHub.