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

  1. Set the handoff's type to exactly 'on_tool_result', 'on_text_mention', or 'on_condition' (lowercase, exact match).
  2. Ensure every entry in the handoffs list is non-null and has a non-null type field.
  3. 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

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


AI-assisted analysis of conductor-oss/conductor@cf7c3e4a8a (2026-08-14). Data as JSON: /api/errors/57779cdeb919b9a8. Report an issue: GitHub.