{"record":{"id":"9817dd30ab83fa64","repo":"dbt-labs/dbt-core","slug":"task-that-doesn-t-belong-to-a-phase-should-overrid","errorCode":null,"errorMessage":"Task that doesn't belong to a phase should override telemetry_tree method","messagePattern":"Task that doesn't belong to a phase should override telemetry_tree method","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-tasks-core/src/task.rs","lineNumber":236,"sourceCode":"        &self,\n        in_dir: &Path,\n        out_dir: &Path,\n        skip_reason: Option<&SkipReason>,\n    ) -> SpanTreeRequest<FsResult<NodeStatus>, SkipReason> {\n        let mut nodes = self.dbt_nodes().into_iter();\n\n        let Some(node) = nodes.next() else {\n            unreachable!(\"Task should always operate on at least a single node\");\n        };\n\n        if nodes.next().is_some() {\n            // task for multiple nodes use current span as task span.\n            // Task inner code should create actual spans for themselves.\n            return SpanTreeRequest::use_current();\n        }\n\n        let Some(task_phase) = self.task_phase() else {\n            unreachable!(\n                \"Task that doesn't belong to a phase should override telemetry_tree method\"\n            );\n        };\n\n        let phase = task_phase.into();\n        let mut attrs = node.get_node_evaluated_event(phase, in_dir, out_dir);\n        if let Some(skip_reason) = skip_reason {\n            update_node_outcome_from_skip_reason(&mut attrs, skip_reason);\n        }\n\n        let task_span_level = match phase {\n            ExecutionPhase::Run | ExecutionPhase::Compare => SpanLevel::Info,\n            _ => SpanLevel::Debug,\n        };\n        let mut builder = SpanTreeRequest::builder(\n            task_span_level,\n            attrs.into(),\n            Some(Box::new(task_span_on_close)),","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-tasks-core/src/task.rs#L218-L254","documentation":"For single-node tasks, telemetry_request needs a TaskPhase to label the span event; phases are obtained via task_phase(), which is only None for task kinds that don't participate in a phase. Such tasks are contractually required to override telemetry_tree with their own span logic, so reaching the None branch here means a phase-less task type was routed through the default telemetry path instead.","triggerScenarios":"Calling telemetry_request on a single-node task whose task_phase() returns None because the task type neither belongs to a phase (build/run/test/etc.) nor overrides telemetry_tree.","commonSituations":"Adding a new task kind (e.g. a utility or docs task) and forgetting to override telemetry_tree; changing a task's phase assignment so it no longer maps to a phase while still inheriting the base implementation.","solutions":["Override telemetry_tree() on the offending task type to supply its own span-tree request.","Give the task a TaskPhase via task_phase() if it logically belongs to an existing phase.","Route phase-less tasks away from the default telemetry_request path in the dispatcher.","Search for newly added Task implementations missing the telemetry_tree override."],"exampleFix":"// before\nimpl MyTask { /* no telemetry_tree override */ }\n\n// after\nfn telemetry_tree(&self) -> SpanTreeRequest<...> {\n    SpanTreeRequest::use_current() // custom span logic for phase-less task\n}","handlingStrategy":"validation","validationCode":"if task.task_phase().is_none() && !task.overrides_telemetry_tree() { /* route to custom span path */ }","typeGuard":"fn needs_phase(task: &dyn AnyTask) -> bool { task.task_phase().is_some() }","tryCatchPattern":null,"preventionTips":["When adding a new task kind, always implement telemetry_tree() if it has no TaskPhase.","Run the trait-implementation checklist for every new Task impl.","Use a compile-time assertion or trait bound tying phase-less tasks to a telemetry_tree override."],"tags":["telemetry","task","trait-implementation","unreachable","rust"],"backgroundTag":"internal-invariant-violation","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}