dbt-labs/dbt-core · error
Unexpected phase
Error message
Unexpected phase: {} What it means
While building the phased task graph for semantic-analysis tasks, cross-phase dependency edges are only expected from Render into the Run or Analyze phases. Any other phase reaching this match indicates the phase enum gained a new variant (or a phase was misrouted) without updating edge construction. The code panics on that unknown phase because no sensible edge target exists.
Solutions
- Extend the match in build_phased_task_graph with an arm for the new phase variant (printing the message shows which one).
- Fix node/dependency bucketing so dependencies only carry Run/Analyze phases where expected.
- Clear stale serialized graph/phase caches after upgrading dbt.
- Audit recent changes to the PhaseTaskVariant enum for missed match arms.
Example fix
// before
TP::Run => runnable_node_index_map.get(dep),
TP::Analyze => analyzeable_node_index_map.get(dep),
_ => unreachable!("Unexpected phase: {}", phase_to_dep),
// after
TP::Run => runnable_node_index_map.get(dep),
TP::Analyze => analyzeable_node_index_map.get(dep),
TP::NewPhase => new_phase_node_index_map.get(dep), Defensive patterns
Strategy: validation
Validate before calling
assert!(matches!(phase_to_dep, TP::Run | TP::Analyze), "unexpected phase {}", phase_to_dep); Type guard
fn is_edge_capable_phase(p: &TP) -> bool { matches!(p, TP::Run | TP::Analyze) } Try / catch
match phase_to_dep {
TP::Run => runnable_node_index_map.get(dep),
TP::Analyze => analyzeable_node_index_map.get(dep),
other => { log::warn!("unexpected phase {other}"); None }
} Prevention
- Exhaustively match phase enums without a catch-all unreachable arm, or use strum's exhaustive iteration in tests.
- Clear stale caches after upgrading dbt versions.
- Update every match on PhaseTaskVariant whenever the enum gains a variant (enable deny(unreachable_patterns)).
When it happens
Trigger: Calling build_phased_task_graph when a dependency's phase_to_dep is neither TP::Run nor TP::Analyze — i.e. a new PhaseTaskVariant was added to the enum but not to this match, or a node was bucketed into an unexpected phase.
Common situations: Upgrading dbt after a new task phase was introduced while cached/serialized phase metadata still carries the old shape; custom forks adding a phase variant without updating graph.rs; a bucketing bug assigning a dependency to the wrong phase.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- cannot consume EOF
- extension dispatch only yields csv as None, not…
- ModelPropertiesSemanticModelConfig is never finalized…
- synthetic relation construction should not fail
- Task should always operate on at least a single node
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/5dfd7fde6967eb21.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-tasks-sa/src/graph.rs:418
} else if phases.contains(&TP::Run) && buckets.in_baseline_or_off_closure(unique_id) {
Some(TP::Run)
} else {
Some(TP::Analyze)
};
if let Some(phase_to_dep) = maybe_phase_to_dep {
if let Some(deps) = schedule.deps.get(unique_id) {
for dep in deps {
if let Some(dep_phases) = node_to_phases.get(dep)
&& dep_phases.contains(&phase_to_dep)
// Never depend on baseline analyze
&& (phase_to_dep == TP::Run || !
buckets.in_baseline_closure(dep))
{
let maybe_from_idx = match phase_to_dep {
TP::Run => runnable_node_index_map.get(dep),
TP::Analyze => analyzeable_node_index_map.get(dep),
_ => unreachable!("Unexpected phase: {}", phase_to_dep),
};
if let (Some(&from_idx), Some(&render_idx)) = (
maybe_from_idx,
node_indices.get(&(TP::Render, unique_id.clone())),
) {
graph.update_edge(from_idx, render_idx, ());
}
}
}
}
}
}
// Add test-to-model run dependencies if fail_fast is enabled - OPTIMIZED
if let Some(run_nodes) = phase_to_nodes.get(&TP::Run) {
add_test_to_model_dependencies(
run_nodes,
&schedule.deps,View on GitHub (pinned to 0267ce9170)