{"record":{"id":"6ae103a92c0160d1","repo":"tinyhumansai/openhuman","slug":"workflow-fan-out-expected-expected-outcomes-res","errorCode":null,"errorMessage":"workflow fan-out: expected {expected_outcomes} result(s), got {}","messagePattern":"workflow fan-out: expected (.+?) result\\(s\\), got (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/orchestration/workflow_runs/engine.rs","lineNumber":728,"sourceCode":"                return Ok(PhaseExecOutcome::Terminated);\n            }\n            Err(err) => return Err(anyhow!(\"workflow fan-out failed: {err}\")),\n        };\n\n        let mut outcomes = Vec::with_capacity(expected_outcomes);\n        for item in outcome.outcomes {\n            match item.result {\n                Ok(value) => outcomes.push(value),\n                Err(err) => {\n                    return Err(anyhow!(\n                        \"workflow fan-out: worker {} failed: {err}\",\n                        item.index\n                    ));\n                }\n            }\n        }\n        if outcomes.len() != expected_outcomes {\n            return Err(anyhow!(\n                \"workflow fan-out: expected {expected_outcomes} result(s), got {}\",\n                outcomes.len()\n            ));\n        }\n\n        // Aggregate worker outcomes in phase order: record every spawned\n        // child id, collect completed outputs, and surface the first failure.\n        for outcome in outcomes {\n            if let Some(oid) = outcome.orchestration_id {\n                spawned_this_phase += 1;\n                child_run_ids.push(oid);\n            }\n            match outcome.output {\n                Some(out) => phase_outputs.push(out),\n                None => {\n                    if phase_failed.is_none() {\n                        phase_failed = outcome.error;\n                    }","sourceCodeStart":710,"sourceCodeEnd":746,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/orchestration/workflow_runs/engine.rs#L710-L746","documentation":"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.","triggerScenarios":"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).","commonSituations":"Executor version drift after upgrading the parallel runner; latent engine bug exposed by cancellation racing the CollectAll aggregation; effectively unseen in normal operation.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match execute_phase(/* ... */).await {\n    Err(e) if e.to_string().contains(\"expected\") && e.to_string().contains(\"result(s), got\") => {\n        // executor contract violation — one retry to rule out a glitch, then report as a bug\n        retry_once_or_report(&config, &run_id, e).await\n    }\n    other => other,\n}","preventionTips":["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"],"tags":["workflow-runs","fan-out","internal-invariant","bug"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}