tokio-rs/tokio · error · syn::Error
`worker_threads` may not be 0.
Error message
`worker_threads` may not be 0.
What it means
`set_worker_threads` (entry.rs:138) parses the value as `usize` and explicitly forbids zero, because a multi-threaded runtime needs at least one worker thread. Zero is nonsensical and would otherwise fail later at runtime builder construction; the macro fails early instead.
Source
Thrown at tokio-macros/src/entry.rs:140
self.flavor = Some(runtime);
Ok(())
}
fn set_worker_threads(
&mut self,
worker_threads: syn::Lit,
span: Span,
) -> Result<(), syn::Error> {
if self.worker_threads.is_some() {
return Err(syn::Error::new(
span,
"`worker_threads` set multiple times.",
));
}
let worker_threads = parse_int(worker_threads, span, "worker_threads")?;
if worker_threads == 0 {
return Err(syn::Error::new(span, "`worker_threads` may not be 0."));
}
self.worker_threads = Some((worker_threads, span));
Ok(())
}
fn set_start_paused(&mut self, start_paused: syn::Lit, span: Span) -> Result<(), syn::Error> {
if self.start_paused.is_some() {
return Err(syn::Error::new(span, "`start_paused` set multiple times."));
}
let start_paused = parse_bool(start_paused, span, "start_paused")?;
self.start_paused = Some((start_paused, span));
Ok(())
}
fn set_crate_name(&mut self, name: syn::Lit, span: Span) -> Result<(), syn::Error> {
if self.crate_name.is_some() {
return Err(syn::Error::new(span, "`crate` set multiple times."));View on GitHub (pinned to 625954f365)
Solutions
- Set `worker_threads` to at least 1 (commonly `std::thread::available_parallelism()`).
- If deriving from configuration, clamp: `max(1, configured_value)`.
- Omit the option to let tokio pick the default (number of CPU cores).
Example fix
// before
#[tokio::main(worker_threads = 0)]
async fn main() {}
// after — let tokio choose, or set a positive count
#[tokio::main(flavor = "multi_thread", worker_threads = 4)]
async fn main() {} Defensive patterns
Strategy: validation
Validate before calling
// If deriving worker count from config, clamp before passing to a manual builder:
let n = config.worker_threads.unwrap_or_else(|| {
std::thread::available_parallelism().map(|n| n.get()).unwrap_or(1)
});
let n = std::cmp::max(1, n);
// Note: the macro requires a literal, so use this only with the runtime builder API. Prevention
- Always use a positive integer for `worker_threads`.
- When computing a count, clamp with `max(1, value)`.
- For dynamic counts, use `tokio::runtime::Builder` instead of the macro.
When it happens
Trigger: Writing `#[tokio::main(worker_threads = 0)]`, or passing a computed value that resolves to 0.
Common situations: Driving `worker_threads` from an environment variable / config without clamping to a minimum of 1; miscounting available parallelism and subtracting one too many.
Related errors
- No such runtime flavor `{s}`. The runtime flavors are `curre
- No such unhandled panic behavior `{s}`. The unhandled panic
- Failed to parse value of `{field}` as integer: {e}
- `name` set multiple times.
- `flavor` set multiple times.
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/f6fb162332656d24.
Report an issue: GitHub.