microsoft/semantic-kernel · error · ArgumentException
The agent {agent.Name ?? agent.Id} cannot have a handoff to
Error message
The agent {agent.Name ?? agent.Id} cannot have a handoff to itself. What it means
Thrown by the HandoffActor constructor when the handoffs map already contains the agent's own name/id. A self-handoff is a no-op that would loop forever (the agent handing control back to itself), so it is rejected at construction with ArgumentException.
Source
Thrown at dotnet/src/Agents/Orchestration/Handoff/HandoffActor.cs:45
private string? _handoffAgent;
private string? _taskSummary;
/// <summary>
/// Initializes a new instance of the <see cref="HandoffActor"/> class.
/// </summary>
/// <param name="id">The unique identifier of the agent.</param>
/// <param name="runtime">The runtime associated with the agent.</param>
/// <param name="context">The orchestration context.</param>
/// <param name="agent">An <see cref="Agent"/>.</param>
/// <param name="handoffs">The handoffs available to this agent</param>
/// <param name="resultHandoff">The handoff agent for capturing the result.</param>
/// <param name="logger">The logger to use for the actor</param>
public HandoffActor(AgentId id, IAgentRuntime runtime, OrchestrationContext context, Agent agent, HandoffLookup handoffs, AgentType resultHandoff, ILogger<HandoffActor>? logger = null)
: base(id, runtime, context, agent, logger)
{
if (handoffs.ContainsKey(agent.Name ?? agent.Id))
{
throw new ArgumentException($"The agent {agent.Name ?? agent.Id} cannot have a handoff to itself.", nameof(handoffs));
}
this._cache = [];
this._handoffs = handoffs;
this._resultHandoff = resultHandoff;
}
/// <summary>
/// Gets or sets the callback to be invoked for interactive input.
/// </summary>
public OrchestrationInteractiveCallback? InteractiveCallback { get; init; }
/// <inheritdoc/>
protected override bool ResponseCallbackFilter(ChatMessageContent response) => response.Role == AuthorRole.Tool;
/// <inheritdoc/>
protected override AgentInvokeOptions CreateInvokeOptions(Func<ChatMessageContent, Task> messageHandler)
{View on GitHub (pinned to c028a0c7dc)
Solutions
- Remove the self-reference from the agent's handoff map.
- When generating handoff maps programmatically, exclude the agent itself.
Example fix
// before
var handoffs = new HandoffLookup { ["writer"] = new() { ["writer"] = new(/*...*/) } };
// after — do not let an agent hand off to itself
var handoffs = new HandoffLookup { ["writer"] = new() { ["reviewer"] = new(/*...*/) } }; Defensive patterns
Strategy: validation
Validate before calling
// Build handoff maps from the member list, excluding self
foreach (var agent in agents)
{
var targets = desiredTargets[agent.Name].Where(n => n != (agent.Name ?? agent.Id));
handoffs[agent.Name] = new(targets.Select(n => new Handoff(n)));
} Prevention
- Never include an agent's own name in its handoff map.
- Generate handoff maps programmatically and filter out self.
- Review handoff definitions for accidental self-references.
When it happens
Trigger: Defining a HandoffOrchestration where an agent's handoff dictionary includes its own Name (or Id when Name is null) as a key.
Common situations: Auto-generated handoff maps that copy every agent into every map; a typo using the agent's own name as a target.
Related errors
- The following agents are not defined in the orchestration: {
- Entry agent is not defined.
- Missing agent description: {agent.Name ?? agent.Id}
- Entry agent is not defined.
- Handoffs cannot be empty. Please provide at least one handof
AI-assisted analysis of microsoft/semantic-kernel@c028a0c7dc (2026-08-13).
Data as JSON: /api/errors/e8d670b367b6c97e.
Report an issue: GitHub.