dbt-labs/dbt-core · critical
failed to initialize 'single-worker' tokio runtime
Error message
failed to initialize 'single-worker' tokio runtime
What it means
`run_cli_with_code` builds a single-worker tokio runtime for the CLI; if `tokio::runtime::Builder::build()` returns Err it panics with this message. Build fails only when the runtime's worker thread cannot be created — typically thread spawn failure from memory/pid limits or a pathological configured stack size.
Solutions
- Check ulimit -u and raise it, or reduce concurrent processes
- Verify container memory/pids cgroup limits and increase them
- Remove or reduce custom stack-size env overrides
- Retry; if persistent, run with RUST_BACKTRACE=1 and report
Example fix
null
Defensive patterns
Strategy: try-catch
Try / catch
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all().build()
.or_else(|_| std::panic::catch_unwind(|| build_default_runtime()))
.expect("no usable tokio runtime"); Prevention
- Verify ulimit -u and cgroup pids before running dbt in containers
- Avoid oversized stack-size env overrides
- Reduce concurrent dbt processes on the host
- Ensure container memory limits leave headroom for thread stacks
When it happens
Trigger: Starting dbt (via `run_cli`) with single-thread mode selected and the OS refusing to create the worker thread: ulimit -u reached, cgroup thread cap, OOM, or `FS_DEFAULT_STACK_SIZE` so large the stack cannot be mmap'd.
Common situations: Containers with tight memory or pids limits; machines under heavy load; mis-sized stack-size env overrides; running many concurrent dbt processes.
Related errors
- failed to initialize default multi-threaded tokio runtime
- {e} {:?}
- {e}
- `crate` set multiple times.
- `EnterGuard` values dropped out of order. Guards returned…
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/02791898fdd7c538.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-main/src/main_impl.rs:167
.build();
// Setup tokio runtime and set stack-size to 8MB
// DO NOT USE Rayon, it is not compatible with Tokio
// Only `--no-parallel` pins the tokio runtime to a single worker.
// `--threads` is exclusively the adapter connection-backpressure knob
// and does not affect the runtime.
let tokio_rt = if arg.no_parallel {
let dbt_rt_handle = dbt_rt.handle().clone();
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.thread_stack_size(FS_DEFAULT_STACK_SIZE)
.worker_threads(1)
.max_blocking_threads(1)
.on_thread_start(move || on_tokio_thread_start(&dbt_rt_handle))
.on_thread_stop(on_tokio_thread_stop)
.build()
.expect("failed to initialize 'single-worker' tokio runtime")
} else {
let dbt_rt_handle = dbt_rt.handle().clone();
// Multi-threaded runtime: use default (max parallelism)
tokio::runtime::Builder::new_multi_thread()
.enable_all()
.max_blocking_threads(FS_DEFAULT_MAX_BLOCKING_THREADS)
.thread_stack_size(FS_DEFAULT_STACK_SIZE)
.on_thread_start(move || on_tokio_thread_start(&dbt_rt_handle))
.on_thread_stop(on_tokio_thread_stop)
.build()
.expect("failed to initialize default multi-threaded tokio runtime")
};
// If execution panics, exit with a status 2 (but not if RUST_BACKTRACE is
// set to 1, in which case we want to see the backtrace):
if arg.exit_process_on_panic && std::env::var("RUST_BACKTRACE").unwrap_or_default() != "1" {
std::panic::set_hook(Box::new(|info| {
eprintln!("{} {}", RED.apply_to(format!("{PANIC}:")), info);View on GitHub (pinned to 0267ce9170)