dbt-labs/dbt-core · error
inconsistent state in unpark
Error message
inconsistent state in unpark
What it means
unpark sets the parker state to NOTIFIED via an atomic swap and expects one of the three legal values. Any other value means the state machine was corrupted, so the library panics instead of attempting to wake a thread in an undefined state. Like error 20, this is an internal invariant guard protecting the thread-parking synchronization protocol.
Source
Thrown at crates/dbt-runtime/src/park.rs:177
match self.state.swap(EMPTY, SeqCst) {
NOTIFIED => {} // got a notification, hurray!
PARKED => {} // no notification, alas
n => panic!("inconsistent park_timeout state: {n}"),
}
}
fn unpark(&self) {
// To ensure the unparked thread will observe any writes we made before
// this call, we must perform a release operation that `park` can
// synchronize with. To do that we must write `NOTIFIED` even if `state`
// is already `NOTIFIED`. That is why this must be a swap rather than a
// compare-and-swap that returns if it reads `NOTIFIED` on failure.
match self.state.swap(NOTIFIED, SeqCst) {
EMPTY => return, // no one was waiting
NOTIFIED => return, // already unparked
PARKED => {} // gotta go wake someone up
_ => panic!("inconsistent state in unpark"),
}
// There is a period between when the parked thread sets `state` to
// `PARKED` (or last checked `state` in the case of a spurious wake
// up) and when it actually waits on `cvar`. If we were to notify
// during this period it would be ignored and then when the parked
// thread went to sleep it would never wake up. Fortunately, it has
// `lock` locked at this stage so we can acquire `lock` to wait until
// it is ready to receive the notification.
//
// Releasing `lock` before the call to `notify_one` means that when the
// parked thread wakes it doesn't get woken only to have to wait for us
// to release `lock`.
drop(self.mutex.lock().unwrap());
self.condvar.notify_one();
}
}View on GitHub (pinned to 0267ce9170)
Solutions
- File a bug with dbt-runtime maintainers including the reproducer; a non-enum value here signals state-machine corruption
- Audit any unsafe code in your workspace that could write to the runtime's internal parker state
- Upgrade dbt-runtime to the latest release to pick up any fixes
- Run the workload under ThreadSanitizer or Miri in tests to locate the corrupting write
Defensive patterns
Strategy: try-catch
Try / catch
// unpark is internal; wrap if exposing custom scheduling
let result = std::panic::catch_unwind(|| parker.unpark());
if result.is_err() { /* treat as corruption; fail fast with diagnostics */ } Prevention
- Never alias or mutate parker internals from unsafe code
- Run under sanitizers when touching concurrency primitives
- Upgrade dbt-runtime before debugging further
- Treat every occurrence as a library bug and report it
When it happens
Trigger: unpark's swap(NOTIFIED, SeqCst) returns a value not in {EMPTY, NOTIFIED, PARKED} — only possible via out-of-band writes to the parker's state atomic (unsafe aliasing, corruption).
Common situations: Not hit in normal usage; appears when debugging concurrent runtimes, fuzzing unsafe code paths, or chasing memory corruption caused elsewhere in the process.
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
- inconsistent park_timeout state: {n}
- inconsistent park state; actual = {actual}
- inconsistent park_timeout state; actual = {actual}
- failed to generate unique thread ID: bitspace exhausted
- waker missing
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/06d529544f9f9851.
Report an issue: GitHub.