microsoft/autogen · error · RuntimeError
Speaker {speaker_name} not found in participant names.
Error message
Speaker {speaker_name} not found in participant names. What it means
Raised at runtime by _transition_to_next_speakers when the group chat manager's speaker-selection step returned a name that is not among the team's participants. The selected name is looked up in the participant-name-to-topic map; a miss means the selector (often an LLM or a custom callback) produced a hallucinated, misspelled, or stale agent name, and routing cannot proceed.
Source
Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_base_group_chat_manager.py:182
await self._transition_to_next_speakers(ctx.cancellation_token)
except Exception as e:
# Handle the exception and signal termination with an error.
error = SerializableException.from_exception(e)
await self._signal_termination_with_error(error)
# Raise the exception to the runtime.
raise
async def _transition_to_next_speakers(self, cancellation_token: CancellationToken) -> None:
speaker_names_future = asyncio.ensure_future(self.select_speaker(self._message_thread))
# Link the select speaker future to the cancellation token.
cancellation_token.link_future(speaker_names_future)
speaker_names = await speaker_names_future
if isinstance(speaker_names, str):
# If only one speaker is selected, convert it to a list.
speaker_names = [speaker_names]
for speaker_name in speaker_names:
if speaker_name not in self._participant_name_to_topic_type:
raise RuntimeError(f"Speaker {speaker_name} not found in participant names.")
await self._log_speaker_selection(speaker_names)
# Send request to publish message to the next speakers
for speaker_name in speaker_names:
speaker_topic_type = self._participant_name_to_topic_type[speaker_name]
await self.publish_message(
GroupChatRequestPublish(),
topic_id=DefaultTopicId(type=speaker_topic_type),
cancellation_token=cancellation_token,
)
self._active_speakers.append(speaker_name)
async def _apply_termination_condition(
self, delta: Sequence[BaseAgentEvent | BaseChatMessage], increment_turn_count: bool = False
) -> bool:
"""Apply the termination condition to the delta and return True if the conversation should be terminated.
It also resets the termination condition and turn count, and signals termination to the caller of the team."""
if self._termination_condition is not None:View on GitHub (pinned to 027ecf0a37)
Solutions
- List the exact participant names in the selector prompt and instruct the model to answer with one of them verbatim.
- If using selector_func, return only names from [a.name for a in participants]; clamp/normalize the LLM output to the closest valid name before returning.
- After changing the team roster, regenerate or update any saved selector prompt/examples and checkpoints.
Example fix
// before
selector = SelectorGroupChat(participants, model_client=client,
selector_prompt="Pick the best agent to speak next.") # names not constrained
// after
names = ', '.join(a.name for a in participants)
selector = SelectorGroupChat(participants, model_client=client,
selector_prompt=f'''Select the next speaker. Reply with EXACTLY one of: {names}. No other text.''') Defensive patterns
Strategy: validation
Validate before calling
valid_names = {a.name for a in participants}
def clamp_selection(names: str | list[str]) -> list[str]:
selected = [names] if isinstance(names, str) else list(names)
unknown = [n for n in selected if n not in valid_names]
if unknown:
raise ValueError(f"Selector returned unknown speakers {unknown}; valid: {sorted(valid_names)}")
return selected Type guard
def is_valid_speaker(name: str, participants: Sequence[ChatAgent]) -> bool:
return name in {p.name for p in participants} Try / catch
try:
async for _ in team.run_stream(task):
pass
except RuntimeError as e:
if "not found in participant names" in str(e):
# fix selector prompt / selector_func, then retry with a fresh team
... Prevention
- Embed the exact participant name list in the selector prompt and demand verbatim answers.
- With selector_func, validate/clamp the returned name against participants before returning it.
- Regenerate selector prompts after any roster change.
When it happens
Trigger: SelectorGroupChat where the LLM selector emits a name not in the participant list (paraphrased, cased differently, or invented); a custom selector_func returning a name of an agent that was removed or renamed; resuming from checkpointed state whose participant set differs from the current team.
Common situations: Selector prompts that describe agents loosely so the model returns e.g. 'CodeReviewer' instead of 'code_reviewer'; changing the agent roster between runs without updating the selector prompt; few-shot examples in the prompt referencing old agent names.
Related errors
- No admin is provided.
- No name is returned.
- Unhandled message in group chat manager: {type(message)}
- Unhandled message in agent container: {type(message)}
- No coder message found
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/e8f058724d162705.
Report an issue: GitHub.