dbt-labs/dbt-core · error · syn::Error
`worker_threads` set multiple times.
Error message
`worker_threads` set multiple times.
What it means
Each #[tokio::main]/#[tokio::test] attribute may specify `worker_threads` at most once. The generated BuildConfig stores Option<worker_threads>; if set_flavor-style setter sees it is already Some, it returns a syn::Error pointing at the duplicate key. This guards against ambiguous configuration rather than silently picking one value.
Source
Thrown at crates/dbt-runtime-macros/src/entry.rs:144
fn set_flavor(&mut self, runtime: syn::Lit, span: Span) -> Result<(), syn::Error> {
if self.flavor.is_some() {
return Err(syn::Error::new(span, "`flavor` set multiple times."));
}
let runtime_str = parse_string(runtime, span, "flavor")?;
let runtime =
RuntimeFlavor::from_str(&runtime_str).map_err(|err| syn::Error::new(span, err))?;
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."));
}
View on GitHub (pinned to 0267ce9170)
Solutions
- Remove the duplicate `worker_threads = N` key, keeping only one
- If you need runtime-configurable thread counts, drop the attribute and build the runtime manually with tokio::runtime::Builder
- Combine the two values into one choice before invoking the macro
Example fix
// before
#[tokio::main(flavor = "multi_thread", worker_threads = 4, worker_threads = 8)]
async fn main() {}
// after
#[tokio::main(flavor = "multi_thread", worker_threads = 8)]
async fn main() {} Defensive patterns
Strategy: validation
Validate before calling
fn check_no_dupes(attr_src: &str, key: &str) -> Result<(), String> {
let n = attr_src.split(',').filter(|p| p.trim().starts_with(key)).count();
if n > 1 { Err(format!("`{key}` specified {n} times")) } else { Ok(()) }
} Prevention
- Keep each attribute on one line to make duplicate keys visually obvious
- Don't merge attribute arguments from multiple examples by hand
- Search the attribute line (Ctrl-F) for the key before adding it again
When it happens
Trigger: Writing #[tokio::main(flavor = "multi_thread", worker_threads = 4, worker_threads = 8)] — the same attribute key appears twice in the token stream passed to build_config.
Common situations: Merging two attribute lines by hand; a macro or code generator emitting the option twice; copy-paste of an attribute line leaving the old worker_threads behind.
Understand the failure class
Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.
Related errors
- `start_paused` set multiple times.
- `crate` set multiple times.
- `unhandled_panic` set multiple times.
- No such runtime flavor `{s}`. The runtime flavors are `curre
- `worker_threads` may not be 0.
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/2d644121779d8c59.
Report an issue: GitHub.