microsoft/semantic-kernel · error · ValueError

Agent {agent_name} is not a member of the handoff group.

Error message

Agent {agent_name} is not a member of the handoff group.

What it means

Raised as a ValueError in _validate_handoffs when an agent that is the SOURCE of a handoff connection is not in the orchestration's members. The validation builds member_names from the members list and checks each handoff's source; a source not present means the handoff graph references an unknown agent, which would break routing.

Source

Thrown at python/semantic_kernel/agents/orchestration/handoffs.py:522

        await asyncio.gather(*[runtime.add_subscription(subscription) for subscription in subscriptions])

    def _get_agent_actor_type(self, agent: Agent, internal_topic_type: str) -> str:
        """Get the actor type for an agent.

        The type is appended with the internal topic type to ensure uniqueness in the runtime
        that may be shared by multiple orchestrations.
        """
        return f"{agent.name}_{internal_topic_type}"

    def _validate_handoffs(self) -> None:
        """Validate the handoffs to ensure all connections are valid."""
        if not self._handoffs:
            raise ValueError("Handoffs cannot be empty. Please provide at least one handoff connection.")

        member_names = {m.name for m in self._members}
        for agent_name, connections in self._handoffs.items():
            if agent_name not in member_names:
                raise ValueError(f"Agent {agent_name} is not a member of the handoff group.")
            for handoff_agent_name in connections:
                if handoff_agent_name not in member_names:
                    raise ValueError(f"Agent {handoff_agent_name} is not a member of the handoff group.")
                if handoff_agent_name == agent_name:
                    raise ValueError(f"Agent {agent_name} cannot handoff to itself.")


# endregion HandoffOrchestration

View on GitHub (pinned to c028a0c7dc)

Solutions

  1. Ensure every handoff source name matches exactly a member's .name.
  2. Pass agent objects directly in Handoff(...) instead of bare strings to avoid typos.
  3. Rebuild handoffs whenever the members list changes.
  4. Trim/normalize agent names to avoid whitespace or casing mismatches.

Example fix

# before - 'triage' is not a member
orchestration = HandoffOrchestration(
    members=[agent_a, agent_b],
    handoffs=[Handoff("triage", agent_b)],
)
# after - source matches a member
orchestration = HandoffOrchestration(
    members=[agent_a, agent_b],
    handoffs=[Handoff(agent_a, agent_b)],
)
Defensive patterns

Strategy: validation

Validate before calling

# Validate all handoff sources are members before constructing:
member_names = {m.name for m in members}
for h in handoffs:
    src = h.source.name if hasattr(h.source, "name") else h.source
    assert src in member_names, f"Handoff source '{src}' is not a member"

Try / catch

try:
    orchestration = HandoffOrchestration(members=members, handoffs=handoffs)
except ValueError as ex:
    if "is not a member" in str(ex):
        # reconcile handoffs with current members and retry
        ...

Prevention

When it happens

Trigger: A Handoff(agent_name_or_object, target) is provided where the source agent's name does not match any member's name. Happens when handoffs reference agents by a different name string, or when members were changed but handoffs were not updated.

Common situations: Renaming an agent after wiring handoffs; typos in handoff source names; passing a Handoff built against a different agent instance; dynamically building members and forgetting to add the source; name collisions or trailing spaces in agent names.

Related errors


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