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
- Set worker_threads >= 1 (or omit it for the default).
- Match macro flavor with options: start_paused and a multi-thread flavor are incompatible.
- Construct the runtime manually with Builder::new_*().build() to surface the real error instead of an expect panic.
- 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
- Use worker_threads >= 1.
- Don't combine incompatible Builder options (e.g. start_paused with multi_thread).
- Prefer manual Builder over the macro when you need error handling at startup.
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
- there is no signal driver running, must be called from the c
- background task failed
- background task failed
- A Tokio 1.x context was found, but IO is disabled. Call `ena
- A Tokio 1.x context was found, but timers are disabled. Call
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/d138a7913c4e5653.
Report an issue: GitHub.