dbt-labs/dbt-core · error · syn::Error
The `worker_threads` option requires the `multi_thread`…
Error message
The `worker_threads` option requires the `multi_thread` runtime flavor. Use `#[{macro_name}(flavor = "multi_thread")]` What it means
The `worker_threads` option only makes sense for the multi_thread flavor; current_thread (and local) runtimes are single-threaded, so the macro's build() validation rejects the combination at compile time and points the error at the worker_threads value's span. The message suggests adding flavor = "multi_thread".
Solutions
- Remove the worker_threads option when using flavor = "current_thread" or "local"
- Change the flavor to "multi_thread" if you actually need multiple workers
- Set the rt-multi-thread feature so multi_thread flavor is available
Example fix
// before
#[tokio::test(flavor = "current_thread", worker_threads = 4)]
async fn t() {}
// after
#[tokio::test(flavor = "current_thread")]
async fn t() {} Defensive patterns
Strategy: validation
Validate before calling
fn check_attr_compat(flavor: &str, worker_threads: Option<u64>) -> Result<(), String> {
if flavor != "multi_thread" && worker_threads.is_some() {
Err(format!("worker_threads requires flavor=\"multi_thread\" (got {flavor})"))
} else { Ok(()) }
} Prevention
- Whenever you change flavor, delete worker_threads in the same edit
- Remember current_thread/local runtimes are single-threaded by design
- Run cargo check immediately after changing test attributes
When it happens
Trigger: #[tokio::main(flavor = "current_thread", worker_threads = 4)] or #[tokio::test(flavor = "current_thread", worker_threads = 2)] — any pairing of current_thread/local flavor with a Some(worker_threads).
Common situations: Switching a test from multi_thread to current_thread for determinism and forgetting to delete worker_threads; cargo feature changes making rt-multi-thread unavailable; copying config across attributes.
Related errors
- `crate` set multiple times.
- No such runtime flavor
- No such unhandled panic behavior
- `start_paused` set multiple times.
- `unhandled_panic` set multiple times.
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/1c35bf9daa864af6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/dbt-runtime-macros/src/entry.rs:215
if self.is_test {
"dbt_runtime::test"
} else {
"dbt_runtime::main"
}
}
fn build(&self) -> Result<FinalConfig, syn::Error> {
use RuntimeFlavor as F;
let flavor = self.flavor.unwrap_or(self.default_flavor);
let worker_threads = match (flavor, self.worker_threads) {
(F::CurrentThread | F::Local, Some((_, worker_threads_span))) => {
let msg = format!(
"The `worker_threads` option requires the `multi_thread` runtime flavor. Use `#[{}(flavor = \"multi_thread\")]`",
self.macro_name(),
);
return Err(syn::Error::new(worker_threads_span, msg));
}
(F::CurrentThread | F::Local, None) => None,
(F::Threaded, worker_threads) if self.rt_multi_thread_available => {
worker_threads.map(|(val, _span)| val)
}
(F::Threaded, _) => {
let msg = if self.flavor.is_none() {
"The default runtime flavor is `multi_thread`, but the `rt-multi-thread` feature is disabled."
} else {
"The runtime flavor `multi_thread` requires the `rt-multi-thread` feature."
};
return Err(syn::Error::new(Span::call_site(), msg));
}
};
let start_paused = match (flavor, self.start_paused) {
(F::Threaded, Some((_, start_paused_span))) => {
let msg = format!(View on GitHub (pinned to 0267ce9170)