Skip to content

Python: [Bug]: Handoff target can be invoked with no messages when the response cleans to empty #7573

Description

@giles17

Description

What happens

HandoffAgentExecutor broadcasts only the cleaned agent response to the other agents and then sends the handoff target a request with no messages:

# _handoff.py:386
cleaned_response = clean_conversation_for_handoff(response.messages)
...
# _handoff.py:395
await self._broadcast_messages(cleaned_response, ctx)
...
# _handoff.py:410-413
await ctx.send_message(
    AgentExecutorRequest(messages=[], should_respond=True),
    target_id=handoff_target,
)

clean_conversation_for_handoff drops every message that has no text content (_orchestrator_helpers.py:41-42). So a response consisting only of tool-control content — function calls, function results, approval payloads — cleans to an empty list.

When that happens the broadcast carries nothing, the handoff target's AgentExecutor cache is left empty (it is cleared after each run, _handoff.py:377), and the target is then invoked with no messages at all.

This is especially reachable in the handoff pattern because the handoff itself is a function call: an agent that hands off without also emitting text produces exactly the tool-only response that cleans away to nothing.

Why it matters

AgentExecutor tolerates an empty cache and only logs a warning, so most chat agents survive. Agents that require input do not — A2AAgent.run raises:

ValueError: At least one message is required when starting a new task (no continuation_token).

which aborts the whole workflow.

Relationship to #7456 / #7549

This is the same root cause as #7456, but in a different orchestrator. PR #7549 fixes the group-chat orchestrators (GroupChatOrchestrator and AgentBasedGroupChatOrchestrator) by supplying a continuation instruction when the selected speaker would otherwise receive no messages. The handoff path was deliberately left out of that PR to keep it scoped to the linked issue.

Suggested fix

Mirror the group-chat fix: when cleaned_response is empty, include an instruction message in the AgentExecutorRequest sent to the handoff target instead of messages=[], so the target is never invoked with empty input. _handoff.py already has a precedent for this shape in _autonomous_mode_prompt (_handoff.py:432), which injects a nudge message for the same class of reason.

Steps to reproduce

  1. Build a handoff workflow where the handing-off agent responds with only a handoff function call and no text content.
  2. Make the handoff target an A2AAgent (or any agent that rejects empty input).
  3. Run the workflow and observe the ValueError when the target is invoked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    pythonUsage: [Issues, PRs], Target: Python

    Type

    No type

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions