Skip to content

Commit 2835d20

Browse files
committed
[Bug] show_dashboard silently downgrades on_error="raise" to "store"
ConcurrentWorkflow documents on_error="raise" as "propagates the exception and aborts the run". _run honours that. run_with_dashboard, which run() dispatches to whenever show_dashboard=True, catches every agent exception unconditionally and records it as that agent's output. So the failure policy quietly depends on whether the dashboard happens to be switched on. A caller who sets on_error="raise" to make agent failures loud gets them swallowed instead, and the run returns a conversation with "Error: ..." where an agent result should be. Mirror the _run branch: re-raise when on_error == "raise", and route the swallowed case through capture_error so the dashboard path stops losing that telemetry too.
1 parent fd9c2e0 commit 2835d20

2 files changed

Lines changed: 58 additions & 0 deletions

File tree

swarms/structs/concurrent_workflow.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,16 @@ def agent_streaming_callback(chunk: str):
410410
output = future.result()
411411
results.append((agent.agent_name, output))
412412
except Exception as e:
413+
if self.on_error == "raise":
414+
raise
415+
# Track the swallowed per-agent failure so it
416+
# isn't lost, same as the non-dashboard path.
417+
capture_error(
418+
e,
419+
self,
420+
name="ConcurrentWorkflow.agent_error",
421+
agent=getattr(agent, "agent_name", None),
422+
)
413423
logger.error(
414424
f"Agent {agent.agent_name} failed: {str(e)}"
415425
)

tests/structs/test_concurrent_workflow.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,5 +490,53 @@ def test_concurrent_workflow_autosave_saves_conversation_after_run(
490490
get_workspace_dir.cache_clear()
491491

492492

493+
class _ExplodingAgent:
494+
"""Minimal agent stand-in whose run() always raises."""
495+
496+
def __init__(self, agent_name: str):
497+
self.agent_name = agent_name
498+
self.print_on = True
499+
500+
def run(self, *args, **kwargs):
501+
raise RuntimeError("agent exploded")
502+
503+
504+
def test_dashboard_path_honors_on_error_raise(monkeypatch):
505+
"""show_dashboard must not downgrade on_error='raise'.
506+
507+
The dashboard path used to swallow every agent exception, so the
508+
documented "propagates the exception and aborts the run" policy
509+
only held while the dashboard was switched off.
510+
"""
511+
workflow = ConcurrentWorkflow(
512+
name="On-Error-Raise-Dashboard",
513+
agents=[_ExplodingAgent("Boom")],
514+
show_dashboard=True,
515+
on_error="raise",
516+
)
517+
monkeypatch.setattr(
518+
workflow, "display_agent_dashboard", lambda *a, **k: None
519+
)
520+
521+
with pytest.raises(RuntimeError, match="agent exploded"):
522+
workflow.run("anything")
523+
524+
525+
def test_dashboard_path_stores_errors_by_default(monkeypatch):
526+
"""on_error='store' still lets the run finish and records the error."""
527+
workflow = ConcurrentWorkflow(
528+
name="On-Error-Store-Dashboard",
529+
agents=[_ExplodingAgent("Boom")],
530+
show_dashboard=True,
531+
)
532+
monkeypatch.setattr(
533+
workflow, "display_agent_dashboard", lambda *a, **k: None
534+
)
535+
536+
workflow.run("anything")
537+
538+
assert "agent exploded" in workflow.conversation.get_str()
539+
540+
493541
if __name__ == "__main__":
494542
pytest.main([__file__, "-v"])

0 commit comments

Comments
 (0)