{"record":{"id":"aa134af344517d2a","repo":"dbt-labs/dbt-core","slug":"the-unhandled-panic-option-requires-the-current","errorCode":null,"errorMessage":"The `unhandled_panic` option requires the `current_thread` runtime flavor. Use `#[{macro_name}(flavor = \"current_thread\")]`","messagePattern":"The `unhandled_panic` option requires the `current_thread` runtime flavor\\. Use `#\\[(.+?)\\(flavor = \"current_thread\"\\)\\]`","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"crates/dbt-runtime-macros/src/entry.rs","lineNumber":249,"sourceCode":"        let start_paused = match (flavor, self.start_paused) {\n            (F::Threaded, Some((_, start_paused_span))) => {\n                let msg = format!(\n                    \"The `start_paused` option requires the `current_thread` runtime flavor. Use `#[{}(flavor = \\\"current_thread\\\")]`\",\n                    self.macro_name(),\n                );\n                return Err(syn::Error::new(start_paused_span, msg));\n            }\n            (F::CurrentThread | F::Local, Some((start_paused, _))) => Some(start_paused),\n            (_, None) => None,\n        };\n\n        let unhandled_panic = match (flavor, self.unhandled_panic) {\n            (F::Threaded, Some((_, unhandled_panic_span))) => {\n                let msg = format!(\n                    \"The `unhandled_panic` option requires the `current_thread` runtime flavor. Use `#[{}(flavor = \\\"current_thread\\\")]`\",\n                    self.macro_name(),\n                );\n                return Err(syn::Error::new(unhandled_panic_span, msg));\n            }\n            (F::CurrentThread | F::Local, Some((unhandled_panic, _))) => Some(unhandled_panic),\n            (_, None) => None,\n        };\n\n        Ok(FinalConfig {\n            name: self.name.clone(),\n            crate_name: self.crate_name.clone(),\n            flavor,\n            worker_threads,\n            start_paused,\n            unhandled_panic,\n        })\n    }\n}\n\nfn parse_int(int: syn::Lit, span: Span, field: &str) -> Result<usize, syn::Error> {\n    match int {","sourceCodeStart":231,"sourceCodeEnd":267,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-runtime-macros/src/entry.rs#L231-L267","documentation":"This compile-time error is produced by the same `FinalConfig::build` step in crates/dbt-runtime-macros/src/entry.rs when the `unhandled_panic` option is set while the resolved runtime flavor is `Threaded` (multi_thread). The `unhandled_panic` knob (e.g. `unhandled_panic = \"abort_runtime\"`) is only implemented for the current_thread/Local runtime flavors in tokio, so the macro rejects the combination with a syn::Error anchored at the `unhandled_panic` argument's span.","triggerScenarios":"Writing `#[dbt_runtime::main(flavor = \"multi_thread\", unhandled_panic = \"abort_runtime\")]` (or the equivalent `#[dbt_runtime::test(...)]`), or omitting the flavor (default multi_thread) while passing `unhandled_panic`. Raised in `build` when flavor == RuntimeFlavor::Threaded and self.unhandled_panic is Some.","commonSituations":"Adding `unhandled_panic = \"abort_runtime\"` to harden a multi-threaded service entry point; copying tokio attribute configuration between runtimes; tests migrated from single-thread tokio tests to multi_thread without auditing options.","solutions":["Switch the flavor to `current_thread`: `#[dbt_runtime::main(flavor = \"current_thread\", unhandled_panic = \"abort_runtime\")]`.","Remove the `unhandled_panic` option if the multi_thread runtime is required.","If panic propagation is the goal on multi_thread, install a panic hook or join spawned tasks explicitly to detect panics instead of using unhandled_panic."],"exampleFix":"// before\n#[dbt_runtime::main(flavor = \"multi_thread\", unhandled_panic = \"abort_runtime\")]\nasync fn main() { /* ... */ }\n\n// after\n#[dbt_runtime::main(flavor = \"current_thread\", unhandled_panic = \"abort_runtime\")]\nasync fn main() { /* ... */ }","handlingStrategy":"validation","validationCode":"// unhandled_panic is only supported on current_thread/local flavors.\nconst FLAVOR: &str = \"multi_thread\";\nconst UNHANDLED_PANIC: Option<&str> = Some(\"abort_runtime\");\nconst _: () = assert!(UNHANDLED_PANIC.is_none() || FLAVOR != \"multi_thread\", \"unhandled_panic requires flavor = \\\"current_thread\\\"\");","typeGuard":"fn is_unhandled_panic_compatible(flavor: &str) -> bool {\n    matches!(flavor, \"current_thread\" | \"local\")\n}","tryCatchPattern":null,"preventionTips":["Audit attribute options whenever you switch a macro between flavor = \"current_thread\" and \"multi_thread\".","Use panic hooks or explicit task joining for panic detection on multi_thread runtimes instead of unhandled_panic.","Keep unhandled_panic = \"abort_runtime\" only in tests that use the single-threaded flavor."],"tags":["rust","macros","tokio","compile-time","runtime-flavor"],"backgroundTag":"conflicting-config-options","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}