microsoft/autogen · error · ValueError
Candidate function must return a non-empty list of participa
Error message
Candidate function must return a non-empty list of participant names.
What it means
SelectorGroupChatManager raises ValueError when a user-supplied candidate_func returns an empty list. The candidate function narrows who may speak next; an empty candidate set leaves the manager no one to select, so it fails fast rather than silently stalling.
Source
Thrown at python/packages/autogen-agentchat/src/autogen_agentchat/teams/_group_chat/_selector_group_chat.py:188
if speaker is not None:
if speaker not in self._participant_names:
raise ValueError(
f"Selector function returned an invalid speaker name: {speaker}. "
f"Expected one of: {self._participant_names}."
)
# Skip the model based selection.
return [speaker]
# Use the candidate function to filter participants if provided
if self._candidate_func is not None:
if self._is_candidate_func_async:
async_candidate_func = cast(AsyncCandidateFunc, self._candidate_func)
participants = await async_candidate_func(thread)
else:
sync_candidate_func = cast(SyncCandidateFunc, self._candidate_func)
participants = sync_candidate_func(thread)
if not participants:
raise ValueError("Candidate function must return a non-empty list of participant names.")
if not all(p in self._participant_names for p in participants):
raise ValueError(
f"Candidate function returned invalid participant names: {participants}. "
f"Expected one of: {self._participant_names}."
)
else:
# Construct the candidate agent list to be selected from, skip the previous speaker if not allowed.
if self._previous_speaker is not None and not self._allow_repeated_speaker:
participants = [p for p in self._participant_names if p != self._previous_speaker]
else:
participants = list(self._participant_names)
assert len(participants) > 0
# Construct agent roles.
# Each agent sould appear on a single line.
roles = ""
for topic_type, description in zip(self._participant_names, self._participant_descriptions, strict=True):View on GitHub (pinned to 027ecf0a37)
Solutions
- Guarantee a non-empty fallback in the candidate function: return filtered or self._participant_names (i.e. fall back to all participants).
- Return None instead of [] if you want the default candidate set (the code only uses the function when it returns a list; ensure every branch returns a non-empty list).
- Log the thread state inside candidate_func when it returns empty to find which condition over-filters.
Example fix
# before
def candidates(thread):
return [p for p in names if p != thread[-1].source] # empty when only 1 participant
# after
def candidates(thread):
filtered = [p for p in names if p != thread[-1].source]
return filtered if filtered else list(names) # never empty Defensive patterns
Strategy: validation
Validate before calling
def candidates(thread):
result = [p for p in participant_names if condition(thread, p)]
return result if result else list(participant_names) # never empty Type guard
def is_nonempty_name_list(value: object) -> bool:
return isinstance(value, list) and len(value) > 0 and all(isinstance(x, str) for x in value) Prevention
- Always provide a fallback candidate set in candidate functions.
- Unit-test candidate functions against the first-turn (empty) thread.
When it happens
Trigger: candidate_func(thread) filters participants and the filter matches nothing, e.g. [p for p in names if some_condition] where the condition is false for all; the function returns [] unconditionally on some code path.
Common situations: Round-robin-style candidate functions that exclude the previous speaker even when only one participant exists; conditions based on message source that never match the current thread state.
Related errors
- Candidate function returned invalid participant names: {part
- Selector function returned an invalid speaker name: {speaker
- At least two participants are required for SelectorGroupChat
- All agents must have a name.
- All agents must have a unique name.
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/d73fc1cc1b9c4c43.
Report an issue: GitHub.