dbt-labs/dbt-core · error
Task that doesn't belong to a phase should override telemetr
Error message
Task that doesn't belong to a phase should override telemetry_tree method
What it means
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.
Source
Thrown at crates/dbt-tasks-core/src/task.rs:236
&self,
in_dir: &Path,
out_dir: &Path,
skip_reason: Option<&SkipReason>,
) -> SpanTreeRequest<FsResult<NodeStatus>, SkipReason> {
let mut nodes = self.dbt_nodes().into_iter();
let Some(node) = nodes.next() else {
unreachable!("Task should always operate on at least a single node");
};
if nodes.next().is_some() {
// task for multiple nodes use current span as task span.
// Task inner code should create actual spans for themselves.
return SpanTreeRequest::use_current();
}
let Some(task_phase) = self.task_phase() else {
unreachable!(
"Task that doesn't belong to a phase should override telemetry_tree method"
);
};
let phase = task_phase.into();
let mut attrs = node.get_node_evaluated_event(phase, in_dir, out_dir);
if let Some(skip_reason) = skip_reason {
update_node_outcome_from_skip_reason(&mut attrs, skip_reason);
}
let task_span_level = match phase {
ExecutionPhase::Run | ExecutionPhase::Compare => SpanLevel::Info,
_ => SpanLevel::Debug,
};
let mut builder = SpanTreeRequest::builder(
task_span_level,
attrs.into(),
Some(Box::new(task_span_on_close)),View on GitHub (pinned to 0267ce9170)
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.
Example fix
// before
impl MyTask { /* no telemetry_tree override */ }
// after
fn telemetry_tree(&self) -> SpanTreeRequest<...> {
SpanTreeRequest::use_current() // custom span logic for phase-less task
} Defensive patterns
Strategy: validation
Validate before calling
if task.task_phase().is_none() && !task.overrides_telemetry_tree() { /* route to custom span path */ } Type guard
fn needs_phase(task: &dyn AnyTask) -> bool { task.task_phase().is_some() } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Task should always operate on at least a single node
- when data_type is date, inner must be a TimeConfig
- ModelPropertiesSemanticModelConfig is never finalized direct
- cannot consume EOF
- synthetic relation construction should not fail: {e}
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/9817dd30ab83fa64.
Report an issue: GitHub.