dbt-labs/dbt-core · error · syn::Error

The `start_paused` option requires the `current_thread` runt

Error message

The `start_paused` option requires the `current_thread` runtime flavor. Use `#[{macro_name}(flavor = "current_thread")]`

What it means

This compile-time error comes from the dbt_runtime macro's config builder in crates/dbt-runtime-macros/src/entry.rs. It fires during `FinalConfig::build` (invoked from `build_config`) when the attribute is given `start_paused = true` while the resolved runtime flavor is `Threaded` (multi_thread). `start_paused` is a tokio testing/pausing feature that only exists on the current_thread (or Local) runtime, so the macro rejects the combination at macro-expansion time with a syn::Error pointing at the `start_paused` argument's span.

Source

Thrown at crates/dbt-runtime-macros/src/entry.rs:237

                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!(
                    "The `start_paused` option requires the `current_thread` runtime flavor. Use `#[{}(flavor = \"current_thread\")]`",
                    self.macro_name(),
                );
                return Err(syn::Error::new(start_paused_span, msg));
            }
            (F::CurrentThread | F::Local, Some((start_paused, _))) => Some(start_paused),
            (_, None) => None,
        };

        let unhandled_panic = match (flavor, self.unhandled_panic) {
            (F::Threaded, Some((_, unhandled_panic_span))) => {
                let msg = format!(
                    "The `unhandled_panic` option requires the `current_thread` runtime flavor. Use `#[{}(flavor = \"current_thread\")]`",
                    self.macro_name(),
                );
                return Err(syn::Error::new(unhandled_panic_span, msg));
            }
            (F::CurrentThread | F::Local, Some((unhandled_panic, _))) => Some(unhandled_panic),
            (_, None) => None,
        };

        Ok(FinalConfig {

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Change the flavor attribute to `flavor = "current_thread"`: e.g. `#[dbt_runtime::main(flavor = "current_thread", start_paused = true)]`.
  2. Remove the `start_paused = true` option if you actually need the multi_thread runtime.
  3. If you need both worker threads and paused time, restructure: run the paused logic inside a `tokio::time::pause()`-friendly current_thread context spawned from the threaded entry, or split tests into current_thread tests.

Example fix

// before
#[dbt_runtime::test(flavor = "multi_thread", start_paused = true)]
async fn my_test() {
    tokio::time::sleep(Duration::from_secs(3600)).await;
}

// after
#[dbt_runtime::test(flavor = "current_thread", start_paused = true)]
async fn my_test() {
    tokio::time::sleep(Duration::from_secs(3600)).await;
}
Defensive patterns

Strategy: validation

Validate before calling

// Compile-time check before using start_paused: it is only valid on current_thread/local flavors.
const FLAVOR: &str = "current_thread";
const START_PAUSED: bool = true;
const _: () = assert!(FLAVOR != "multi_thread" || !START_PAUSED, "start_paused requires flavor = \"current_thread\"");
#[dbt_runtime::test(flavor = "current_thread", start_paused = true)]
async fn t() {}

Type guard

fn is_start_paused_compatible(flavor: &str) -> bool {
    matches!(flavor, "current_thread" | "local")
}

Prevention

When it happens

Trigger: Writing `#[dbt_runtime::main(flavor = "multi_thread", start_paused = true)]` (or `#[dbt_runtime::test(...)]` with the same combo), or relying on the default flavor being multi_thread while passing only `start_paused = true`. Raised in `build` when flavor == RuntimeFlavor::Threaded and self.start_paused is Some.

Common situations: Copying a test that uses `#[tokio::test(start_paused = true)]` and adding a multi_thread flavor for heavier tests; enabling start_paused to use tokio time auto-advance while forgetting that pause requires a single-threaded runtime; migrating tokio attribute args to dbt_runtime without knowing flavor constraints.

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


AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/b87c81454967c9a1. Report an issue: GitHub.