conductor-oss/conductor · error · IllegalArgumentException
SWARM handoff type must be on_tool_result, on_text_mention,
Error message
SWARM handoff type must be on_tool_result, on_text_mention, or on_condition
What it means
Thrown during agent compilation when a SWARM-strategy agent's handoff entry has a 'type' that is not one of the three supported trigger types: 'on_tool_result', 'on_text_mention', or 'on_condition'. The validator iterates every HandoffConfig in config.getHandoffs() and also fires if the handoff object itself is null. This is a compile-time gate so misconfigured handoffs surface at deploy, not at runtime when the coordinator silently ignores them.
Source
Thrown at agentspan/src/main/java/org/conductoross/conductor/ai/agentspan/runtime/compiler/MultiAgentCompiler.java:1489
targets.put(tool.getName(), tool.getName().substring(index + marker.length()));
}
return targets;
}
/** Validate the declarative SWARM contract without changing its wire representation. */
private static void validateSwarmHandoffs(AgentConfig config) {
if (config.getHandoffs() == null) return;
Set<String> targets = new HashSet<>();
targets.add(config.getName());
if (config.getAgents() != null) {
for (AgentConfig agent : config.getAgents()) targets.add(agent.getName());
}
for (HandoffConfig handoff : config.getHandoffs()) {
if (handoff == null
|| handoff.getType() == null
|| !Set.of("on_tool_result", "on_text_mention", "on_condition")
.contains(handoff.getType())) {
throw new IllegalArgumentException(
"SWARM handoff type must be on_tool_result, on_text_mention, or on_condition");
}
if (handoff.getTarget() == null || !targets.contains(handoff.getTarget())) {
throw new IllegalArgumentException(
"SWARM handoff target must name a swarm agent: " + handoff.getTarget());
}
switch (handoff.getType()) {
case "on_tool_result" -> {
if (isBlank(handoff.getToolName()) || isBlank(handoff.getResultContains())) {
throw new IllegalArgumentException(
"on_tool_result requires toolName and resultContains");
}
}
case "on_text_mention" -> {
if (isBlank(handoff.getText())) {
throw new IllegalArgumentException("on_text_mention requires text");
}
}View on GitHub (pinned to cf7c3e4a8a)
Solutions
- Set the handoff's type to exactly 'on_tool_result', 'on_text_mention', or 'on_condition' (lowercase, exact match).
- Ensure every entry in the handoffs list is non-null and has a non-null type field.
- Remove any null or placeholder entries from the handoffs array.
Example fix
// before
{"type": "on_tool_results", "target": "researcher"}
// after
{"type": "on_tool_result", "target": "researcher", "toolName": "search", "resultContains": "complete"} Defensive patterns
Strategy: validation
Validate before calling
private static final Set<String> VALID_HANDOFF_TYPES =
Set.of("on_tool_result", "on_text_mention", "on_condition");
void validateHandoffTypes(List<HandoffConfig> handoffs) {
if (handoffs == null) return;
for (int i = 0; i < handoffs.size(); i++) {
HandoffConfig h = handoffs.get(i);
if (h == null || !VALID_HANDOFF_TYPES.contains(h.getType())) {
throw new IllegalArgumentException(
"handoffs[" + i + "] has invalid type; expected one of " + VALID_HANDOFF_TYPES);
}
}
} Try / catch
try {
compiler.compile(agentConfig);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("handoff type must be")) {
// fix the handoff type in config and recompile
}
throw e;
} Prevention
- Define handoff type strings as constants or an enum instead of string literals.
- Validate handoff configs in a unit test before deploying.
When it happens
Trigger: An AgentConfig with strategy=SWARM whose handoffs list contains an entry whose type field is null, misspelled (e.g. 'on_tool_results', 'On_Tool_Result'), or uses an unsupported value. Also triggers when a null entry exists in the handoffs list.
Common situations: Typo in the JSON/Python config (plural 'on_tool_results' instead of singular), copy-pasting handoff type strings from OpenAI Agents SDK docs that use slightly different names, or omitting the type field entirely from a handoff definition. Common when handoffs are constructed programmatically and the type constant is wrong.
Related errors
- SWARM handoff target must name a swarm agent: ${handoff.getT
- on_tool_result requires toolName and resultContains
- on_text_mention requires text
- on_condition requires a nonblank taskName
- Sub-agent name '${a.getName()}' in '${config.getName()}' is
AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14).
Data as JSON: /api/errors/57779cdeb919b9a8.
Report an issue: GitHub.