kyegomez/swarms

[Improvement] ConcurrentWorkflow aborts the whole run when any single agent fails

Open

#1,613 opened on May 14, 2026

View on GitHub
 (2 comments) (0 reactions) (0 assignees)Python (948 forks)github user discovery
FEATenhancementgood first issuehelp wanted

Repository metrics

Stars
 (6,809 stars)
PR merge metrics
 (PR metrics pending)

Description

Summary

In ConcurrentWorkflow, one failed agent kills the entire run and discards all sibling outputs that already completed successfully. This contradicts the design goal of independent concurrent execution.

Repro

from swarms import Agent, ConcurrentWorkflow

a = Agent(agent_name="Good-1", model_name="gpt-4.1", max_loops=1)
b = Agent(agent_name="Good-2", model_name="gpt-4.1", max_loops=1)
c = Agent(agent_name="Bad",    model_name="gpt-4.1", max_loops=1)
c.run = lambda *a, **kw: (_ for _ in ()).throw(RuntimeError("boom"))

wf = ConcurrentWorkflow(agents=[a, b, c])
wf.run("Summarise the news today.")
# Expected: results for Good-1 and Good-2, plus an error marker for Bad.
# Actual:   RuntimeError propagates out — Good-1 and Good-2's outputs are lost.

Root cause

swarms/structs/concurrent_workflow.py:418-425 does not wrap future.result() in a try/except:

for future in as_completed(futures):
    output = future.result()        # raises on any failed worker
    self.conversation.add(...)

The dashboard variant already handles this correctly at concurrent_workflow.py:346-356. The non-dashboard path was missed.

Proposed fix

Wrap future.result() in try/except mirroring the dashboard path. On error, append a clearly-labeled error entry to the conversation (e.g., role f"{agent_name} (failed)") so callers can filter it, and continue collecting sibling results.

Add an opt-in constructor flag for users who prefer the old behavior:

on_error: Literal["raise", "store"] = "store"

"store" (default) collects per-agent errors and returns partial results. "raise" preserves today's fail-fast behavior.

Tests to add

  • ConcurrentWorkflow with one failing agent and two passing agents: assert partial results returned, failed agent's error captured under its name, no exception escapes.
  • on_error="raise": assert the exception still propagates.

Contributor guide