tinyhumansai/openhuman · error
workflow scheduler graph compile failed: {e}
Error message
workflow scheduler graph compile failed: {e} What it means
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.
Source
Thrown at src/openhuman/agent/orchestration/workflow_runs/graph.rs:137
.with_goto(["dispatch"]),
)),
PhaseExecOutcome::Terminated => {
Ok(NodeResult::Command(Command::default().with_goto(["done"])))
}
}
}
});
let graph = builder
.add_node("done", |_s: SchedulerState, _c: NodeContext| async move {
Ok(NodeResult::Update(SchedulerUpdate::Noop))
})
.set_entry("dispatch")
.mark_command_routing("dispatch")
.mark_command_routing("run_phase")
.set_finish("done")
.compile()
.map_err(|e| anyhow!("workflow scheduler graph compile failed: {e}"))?
// Bound the dispatch⇄run_phase cycle as a backstop to the DAG's own
// termination: `dispatch` is visited once per phase plus a final
// no-phase visit, `run_phase` once per phase. A validated DAG always
// drains, so this only guards a malformed definition.
.with_recursion_policy(RecursionPolicy {
max_visits_per_node: Some(phase_count + 2),
max_total_steps: (phase_count + 1) * 3 + 16,
..RecursionPolicy::default()
});
Ok(graph)
}
/// Topologically walk the phase DAG on a `tinyagents` conditional-routing graph
/// (issue #4249, Phase 4): a `dispatch` node selects the next runnable phase and
/// a `run_phase` node executes it, looping `dispatch ⇄ run_phase` until no phase
/// remains, then routing to `done`:
///
/// ```textView on GitHub (pinned to a221052e0d)
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
Example fix
// before — goto target typo, no such node
Command::default().with_goto(["run_phases"])
// after — matches add_node("run_phase", ...)
Command::default().with_goto(["run_phase"]) Defensive patterns
Strategy: validation
Validate before calling
// Rust — pin the scheduler topology in CI; scheduler_graph_topology()
// compiles the exact same builder with stub effects.
#[test]
fn scheduler_graph_compiles() {
let _ = scheduler_graph_topology()
.expect("workflow scheduler graph must always compile");
} Try / catch
// Treat as a programmer error, never a runtime condition to retry:
match build_scheduler_graph(n, select, run) {
Ok(g) => g,
Err(e) => {
tracing::error!("scheduler topology bug: {e:#}");
return Err(e);
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- workflow scheduler graph run failed: {e}
- turn model source is missing a model
- voice_not_compiled
- Runtime unavailable: ${runtime.runtime} (${runtime.error ??
- spawned core exited with ${child.exitCode} ${stderrFn()}
AI-assisted analysis of tinyhumansai/openhuman@a221052e0d (2026-08-16).
Data as JSON: /api/errors/25c35c6ff0648c67.
Report an issue: GitHub.