dbt-labs/dbt-core · error
this should be handled somewhere else
Error message
this should be handled somewhere else
What it means
When a task succeeds, the visitor maps its NodeStatus to downstream propagation actions. The SkippedUpstreamFailed status is contractually converted earlier (it should never appear as a task result at this point), so encountering it in this match means upstream-failure handling was bypassed and the code panics rather than propagating skips incorrectly.
Solutions
- Find where the task result status is set and ensure SkippedUpstreamFailed is handled there (mark dependents skipped without calling handle_task_result).
- Add an explicit early-return arm for SkippedUpstreamFailed in handle_task_result that performs the skip propagation instead of panicking.
- Check custom status transitions for leaked SkippedUpstreamFailed outcomes.
- Reproduce with the failing node's unique_id and trace which code path assigned the status.
Example fix
// before
NodeStatus::SkippedUpstreamFailed => unreachable!("this should be handled somewhere else"),
// after
NodeStatus::SkippedUpstreamFailed => self.propagate_skipped(task_idx, dependents, schedule), Defensive patterns
Strategy: validation
Validate before calling
if result.status == NodeStatus::SkippedUpstreamFailed { return; } // handled by skip propagation elsewhere Type guard
fn is_success_path_status(s: &NodeStatus) -> bool { !matches!(s, NodeStatus::SkippedUpstreamFailed) } Try / catch
match status {
NodeStatus::SkippedUpstreamFailed => return Ok(()), // handled upstream; do not re-process
other => handle_task_result_inner(other),
} Prevention
- Convert SkippedUpstreamFailed into dependent-skip actions at the point it is produced, never as a task result.
- Keep NodeStatus transition logic centralized so statuses cannot leak into the wrong handler.
- Add a test asserting SkippedUpstreamFailed never reaches handle_task_result.
When it happens
Trigger: Calling handle_task_result (from visit or the state-comparison test visitor paths) with a task result whose NodeStatus is SkippedUpstreamFailed — i.e. a status that should have been translated before entering the success-handling match.
Common situations: A scheduling/propagation bug records SkippedUpstreamFailed as the task's own outcome instead of skipping via dependents; custom forks or modified status transitions leak the status into the visitor; state:test flows (reused-model preemption logic) producing this status from a different code path than the main run visitor.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 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/51243c6a40646b6c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-tasks-sa/src/visitor.rs:265
Vec::new(),
if reuse_downstream_tests {
// TODO: Unfortunately, we have diverging logic for data tests vs all other node types,
// when it comes to upstream being reused. All other node tasks will run and just
// report themselves as reused, but for tests we have historically propagated skips
// in the visitor. This should be unified eventually.
self.propagate_reuse_to_downstream_tests(task_idx, dependents, schedule)
} else {
Vec::new()
},
),
NodeStatus::Succeeded
| NodeStatus::SucceededWithWarning
| NodeStatus::TestPassed
| NodeStatus::StaticallyCheckedDataTest
| NodeStatus::TestWarned
| NodeStatus::NoOp => (Vec::new(), Vec::new()),
NodeStatus::SkippedUpstreamFailed => {
unreachable!("this should be handled somewhere else")
}
},
Err(_) => (
self.propagate_failure(task_idx, dependents, schedule),
Vec::new(),
),
}
}
}
// Returns true when the failing task is a model with `on_error: continue`.
//
// Phase gating: honored for Render and Run failures, but **not** Analyze.
// Analyze produces the type/binding facts that `--static-analysis strict`
// downstreams consume, so upstream Analyze failures must still propagate.
//
// TODO: The correct rule is per-downstream — propagate Render/Analyze
// failure only to downstreams whose `static_analysis` is `strict`. TheView on GitHub (pinned to 0267ce9170)