tokio-rs/tokio · critical

Failed building the Runtime

Error message

Failed building the Runtime

What it means

The #[tokio::main] / #[tokio::test] macro generates a .expect("Failed building the Runtime") call on the runtime builder. It panics at process startup if Builder::build() returns Err — e.g. invalid worker/thread counts or platform runtime construction failure.

Source

Thrown at tokio-macros/src/entry.rs:518

        quote! {
            #[::core::prelude::v1::test]
        }
    } else {
        quote! {}
    };

    let body_ident = quote! { body };
    // This explicit `return` is intentional. See tokio-rs/tokio#4636
    let last_block = quote_spanned! {last_stmt_end_span=>

        #[allow(clippy::expect_used, clippy::diverging_sub_expression, clippy::needless_return, clippy::unwrap_in_result)]
        {
            #use_builder

            return #rt
                .enable_all()
                .#build
                .expect("Failed building the Runtime")
                .block_on(#body_ident);
        }

    };

    let body = input.body();

    // For test functions pin the body to the stack and use `Pin<&mut dyn
    // Future>` to reduce the amount of `Runtime::block_on` (and related
    // functions) copies we generate during compilation due to the generic
    // parameter `F` (the future to block on). This could have an impact on
    // performance, but because it's only for testing it's unlikely to be very
    // large.
    //
    // We don't do this for the main function as it should only be used once so
    // there will be no benefit.
    let output_type = match &input.sig.output {
        // For functions with no return value syn doesn't print anything,

View on GitHub (pinned to 625954f365)

Solutions

  1. Set worker_threads >= 1 (or omit it for the default).
  2. Match macro flavor with options: start_paused and a multi-thread flavor are incompatible.
  3. Construct the runtime manually with Builder::new_*().build() to surface the real error instead of an expect panic.
  4. Check target platform support for the runtime features requested.

Example fix

// before
#[tokio::main(flavor = "multi_thread", worker_threads = 0)]
async fn main() {}
// after
#[tokio::main(flavor = "multi_thread", worker_threads = 1)]
async fn main() {}
Defensive patterns

Strategy: validation

Validate before calling

// Build the runtime manually to surface the real error instead of an expect panic:
let rt = tokio::runtime::Builder::new_multi_thread()
    .worker_threads(2)
    .enable_all()
    .build()?; // returns Result

Try / catch

// Macro path panics; switch to manual build to catch:
match tokio::runtime::Builder::new_multi_thread().enable_all().build() {
    Ok(rt) => rt.block_on(main_async()),
    Err(e) => { eprintln!("runtime build failed: {e}"); std::process::exit(1); }
}

Prevention

When it happens

Trigger: Using #[tokio::main(flavor = "...", worker_threads = N, ...)] with parameters Builder rejects; calling #[tokio::main] on a platform where runtime construction is unsupported.

Common situations: Setting worker_threads = 0; using start_paused without current-thread flavor; wasm/wasi targets lacking full runtime support; build options incompatible with the chosen flavor.

Related errors


AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11). Data as JSON: /api/errors/d138a7913c4e5653. Report an issue: GitHub.