dbt-labs/dbt-core · critical

failed to initialize default multi-threaded tokio runtime

Error message

failed to initialize default multi-threaded tokio runtime

What it means

`run_cli_with_code` builds the default multi-threaded tokio runtime when multi-thread mode is enabled; `.build()` failure panics with this message. As with the single-worker path, the only realistic cause is the OS failing to create worker threads (thread/pid limits, OOM, oversized stacks).

Solutions

  1. Raise ulimit -u / container pids limit
  2. Increase container memory or reduce FS_DEFAULT_MAX_BLOCKING_THREADS / stack size
  3. Lower parallelism (e.g. --threads) or run on a less constrained machine
  4. Set RUST_BACKTRACE=1 and report if it persists on a normal machine

Example fix

null
Defensive patterns

Strategy: try-catch

Try / catch

let rt = tokio::runtime::Builder::new_multi_thread()
    .enable_all().build()
    .unwrap_or_else(|e| panic!("runtime init failed: {e}; check ulimit -u and memory"));

Prevention

When it happens

Trigger: `run_cli` → `run_cli_with_code` selects the multi-thread branch and `tokio::runtime::Builder::new_multi_thread().build()` fails because worker threads cannot be spawned (ulimit, cgroup pids, memory exhaustion) or `FS_DEFAULT_MAX_BLOCKING_THREADS`/stack size settings are unusable.

Common situations: High-core-count machines spawning many worker threads in a constrained container; heavy parallel dbt load; low `ulimit -u`; invalid huge FS_DEFAULT_STACK_SIZE.

Related errors


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/378c80be725ef513. Report an issue: GitHub.

Appendix: source

Thrown at crates/dbt-main/src/main_impl.rs:178

            .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);
            let _ = io::stdout().flush();
            let _ = io::stderr().flush();

            std::process::exit(2);
        }));
    }

    let cst = feature_stack.cli.cancellation_token_source.clone();
    let fail_fast = feature_stack.cli.fail_fast.clone();
    let token = cst.token();

View on GitHub (pinned to 0267ce9170)