{"record":{"id":"25c35c6ff0648c67","repo":"tinyhumansai/openhuman","slug":"workflow-scheduler-graph-compile-failed-e","errorCode":null,"errorMessage":"workflow scheduler graph compile failed: {e}","messagePattern":"workflow scheduler graph compile failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/openhuman/agent/orchestration/workflow_runs/graph.rs","lineNumber":137,"sourceCode":"                        .with_goto([\"dispatch\"]),\n                )),\n                PhaseExecOutcome::Terminated => {\n                    Ok(NodeResult::Command(Command::default().with_goto([\"done\"])))\n                }\n            }\n        }\n    });\n\n    let graph = builder\n        .add_node(\"done\", |_s: SchedulerState, _c: NodeContext| async move {\n            Ok(NodeResult::Update(SchedulerUpdate::Noop))\n        })\n        .set_entry(\"dispatch\")\n        .mark_command_routing(\"dispatch\")\n        .mark_command_routing(\"run_phase\")\n        .set_finish(\"done\")\n        .compile()\n        .map_err(|e| anyhow!(\"workflow scheduler graph compile failed: {e}\"))?\n        // Bound the dispatch⇄run_phase cycle as a backstop to the DAG's own\n        // termination: `dispatch` is visited once per phase plus a final\n        // no-phase visit, `run_phase` once per phase. A validated DAG always\n        // drains, so this only guards a malformed definition.\n        .with_recursion_policy(RecursionPolicy {\n            max_visits_per_node: Some(phase_count + 2),\n            max_total_steps: (phase_count + 1) * 3 + 16,\n            ..RecursionPolicy::default()\n        });\n    Ok(graph)\n}\n\n/// Topologically walk the phase DAG on a `tinyagents` conditional-routing graph\n/// (issue #4249, Phase 4): a `dispatch` node selects the next runnable phase and\n/// a `run_phase` node executes it, looping `dispatch ⇄ run_phase` until no phase\n/// remains, then routing to `done`:\n///\n/// ```text","sourceCodeStart":119,"sourceCodeEnd":155,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/src/openhuman/agent/orchestration/workflow_runs/graph.rs#L119-L155","documentation":"Thrown when GraphBuilder::compile() rejects the workflow scheduler graph's topology (graph.rs:137). compile() validates that set_entry(\"dispatch\") and set_finish(\"done\") reference registered nodes, that every with_goto([...]) target exists, and that command-emitting nodes are marked with mark_command_routing. Because dispatch/run_phase/done are all registered in the same hardcoded function, this error signals an internal invariant break in the scheduler module (or an incompatible tinyagents graph API change), not user configuration.","triggerScenarios":"Renaming a node in build_scheduler_graph without updating the matching with_goto strings; adding Command::default().with_goto([\"new_node\"]) without add_node(\"new_node\", ...); pointing set_entry/set_finish at a removed node; a tinyagents upgrade that tightens compile-time topology validation.","commonSituations":"Refactors of workflow_runs/graph.rs (issue #4249 follow-ups); copy-pasted node blocks missing their add_node registration; CI breakage right after a tinyagents crate bump.","solutions":["Diff every with_goto target and set_entry/set_finish name against the add_node names in build_scheduler_graph — they must match exactly","Add/keep a unit test calling scheduler_graph_topology() (same builder, stub effects) so topology drift fails CI instead of runtime","If it appears after a tinyagents version bump, read its compile() rules for newly required marks such as mark_command_routing","Treat any occurrence in a shipped build as a bug: capture the backtrace and file an issue"],"exampleFix":"// before — goto target typo, no such node\nCommand::default().with_goto([\"run_phases\"])\n\n// after — matches add_node(\"run_phase\", ...)\nCommand::default().with_goto([\"run_phase\"])","handlingStrategy":"validation","validationCode":"// Rust — pin the scheduler topology in CI; scheduler_graph_topology()\n// compiles the exact same builder with stub effects.\n#[test]\nfn scheduler_graph_compiles() {\n    let _ = scheduler_graph_topology()\n        .expect(\"workflow scheduler graph must always compile\");\n}","typeGuard":null,"tryCatchPattern":"// Treat as a programmer error, never a runtime condition to retry:\nmatch build_scheduler_graph(n, select, run) {\n    Ok(g) => g,\n    Err(e) => {\n        tracing::error!(\"scheduler topology bug: {e:#}\");\n        return Err(e);\n    }\n}","preventionTips":["Never reference a node name in with_goto/set_entry/set_finish that is not an add_node argument in the same function","Keep scheduler_graph_topology() under test so the structure-only export doubles as a compile check","Re-run the graph tests after any tinyagents version bump"],"tags":["rust","workflow","dag","graph","internal-invariant"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}