tinyhumansai/openhuman · error
workflow fan-out: expected {expected_outcomes} result(s), go
Error message
workflow fan-out: expected {expected_outcomes} result(s), got {} What it means
Defensive invariant check after a workflow phase fan-out: the number of collected worker outcomes must equal expected_outcomes (the number of agents the phase submitted, after any max_children cap). Under FailurePolicy::CollectAll the executor should always return exactly one outcome per input; a mismatch means results were dropped or duplicated by the executor — an internal bug, not a caller error.
Source
Thrown at src/openhuman/agent/orchestration/workflow_runs/engine.rs:728
return Ok(PhaseExecOutcome::Terminated);
}
Err(err) => return Err(anyhow!("workflow fan-out failed: {err}")),
};
let mut outcomes = Vec::with_capacity(expected_outcomes);
for item in outcome.outcomes {
match item.result {
Ok(value) => outcomes.push(value),
Err(err) => {
return Err(anyhow!(
"workflow fan-out: worker {} failed: {err}",
item.index
));
}
}
}
if outcomes.len() != expected_outcomes {
return Err(anyhow!(
"workflow fan-out: expected {expected_outcomes} result(s), got {}",
outcomes.len()
));
}
// Aggregate worker outcomes in phase order: record every spawned
// child id, collect completed outputs, and surface the first failure.
for outcome in outcomes {
if let Some(oid) = outcome.orchestration_id {
spawned_this_phase += 1;
child_run_ids.push(oid);
}
match outcome.output {
Some(out) => phase_outputs.push(out),
None => {
if phase_failed.is_none() {
phase_failed = outcome.error;
}View on GitHub (pinned to a221052e0d)
Solutions
- Retry the run via resume_workflow_run to rule out a one-off aggregation glitch
- Capture expected vs got counts plus engine/executor versions and report as a bug against the workflow engine or tinyagents
- Pin matching engine/executor versions until fixed
Defensive patterns
Strategy: try-catch
Try / catch
match execute_phase(/* ... */).await {
Err(e) if e.to_string().contains("expected") && e.to_string().contains("result(s), got") => {
// executor contract violation — one retry to rule out a glitch, then report as a bug
retry_once_or_report(&config, &run_id, e).await
}
other => other,
} Prevention
- Pin engine and tinyagents executor versions together — this invariant breaks at their seam
- Include expected/got counts from the message in any bug report
- Do not attempt caller-side workarounds; no input can legitimately produce this error
When it happens
Trigger: Cannot be produced by any argument or configuration; it fires only if the map_reduce executor violates its one-outcome-per-input contract (count mismatch after all Ok/Err results are folded).
Common situations: Executor version drift after upgrading the parallel runner; latent engine bug exposed by cancellation racing the CollectAll aggregation; effectively unseen in normal operation.
Related errors
- workflow run {run_id} vanished mid-loop
- workflow run {run_id} vanished mid-phase
- workflow fan-out failed: {err}
- workflow fan-out: worker {} failed: {err}
- team missing after creation: {team_id}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/6ae103a92c0160d1.
Report an issue: GitHub.