{"record":{"id":"5dfd7fde6967eb21","repo":"dbt-labs/dbt-core","slug":"unexpected-phase","errorCode":null,"errorMessage":"Unexpected phase: {}","messagePattern":"Unexpected phase: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-tasks-sa/src/graph.rs","lineNumber":418,"sourceCode":"            } else if phases.contains(&TP::Run) && buckets.in_baseline_or_off_closure(unique_id) {\n                Some(TP::Run)\n            } else {\n                Some(TP::Analyze)\n            };\n\n            if let Some(phase_to_dep) = maybe_phase_to_dep {\n                if let Some(deps) = schedule.deps.get(unique_id) {\n                    for dep in deps {\n                        if let Some(dep_phases) = node_to_phases.get(dep)\n                        && dep_phases.contains(&phase_to_dep)\n                        // Never depend on baseline analyze\n                        && (phase_to_dep == TP::Run || !\n                            buckets.in_baseline_closure(dep))\n                        {\n                            let maybe_from_idx = match phase_to_dep {\n                                TP::Run => runnable_node_index_map.get(dep),\n                                TP::Analyze => analyzeable_node_index_map.get(dep),\n                                _ => unreachable!(\"Unexpected phase: {}\", phase_to_dep),\n                            };\n                            if let (Some(&from_idx), Some(&render_idx)) = (\n                                maybe_from_idx,\n                                node_indices.get(&(TP::Render, unique_id.clone())),\n                            ) {\n                                graph.update_edge(from_idx, render_idx, ());\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        // Add test-to-model run dependencies if fail_fast is enabled - OPTIMIZED\n        if let Some(run_nodes) = phase_to_nodes.get(&TP::Run) {\n            add_test_to_model_dependencies(\n                run_nodes,\n                &schedule.deps,","sourceCodeStart":400,"sourceCodeEnd":436,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-tasks-sa/src/graph.rs#L400-L436","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nTP::Run => runnable_node_index_map.get(dep),\nTP::Analyze => analyzeable_node_index_map.get(dep),\n_ => unreachable!(\"Unexpected phase: {}\", phase_to_dep),\n\n// after\nTP::Run => runnable_node_index_map.get(dep),\nTP::Analyze => analyzeable_node_index_map.get(dep),\nTP::NewPhase => new_phase_node_index_map.get(dep),","handlingStrategy":"validation","validationCode":"assert!(matches!(phase_to_dep, TP::Run | TP::Analyze), \"unexpected phase {}\", phase_to_dep);","typeGuard":"fn is_edge_capable_phase(p: &TP) -> bool { matches!(p, TP::Run | TP::Analyze) }","tryCatchPattern":"match phase_to_dep {\n    TP::Run => runnable_node_index_map.get(dep),\n    TP::Analyze => analyzeable_node_index_map.get(dep),\n    other => { log::warn!(\"unexpected phase {other}\"); None }\n}","preventionTips":["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))."],"tags":["task-graph","enum","phases","unreachable","rust"],"backgroundTag":"invalid-enum-value","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}