dbt-labs/dbt-core · error · syn::Error
`unhandled_panic` set multiple times.
Error message
`unhandled_panic` set multiple times.
What it means
The `unhandled_panic` option may be given at most once per #[tokio::main]/#[tokio::test]. set_unhandled_panic checks its stored Option and raises a syn::Error at the duplicate key if it is already set, before even validating the value.
Source
Thrown at crates/dbt-runtime-macros/src/entry.rs:183
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."));
}
let name_path = parse_path(name, span, "crate")?;
self.crate_name = Some(name_path);
Ok(())
}
fn set_unhandled_panic(
&mut self,
unhandled_panic: syn::Lit,
span: Span,
) -> Result<(), syn::Error> {
if self.unhandled_panic.is_some() {
return Err(syn::Error::new(
span,
"`unhandled_panic` set multiple times.",
));
}
let unhandled_panic = parse_string(unhandled_panic, span, "unhandled_panic")?;
let unhandled_panic =
UnhandledPanic::from_str(&unhandled_panic).map_err(|err| syn::Error::new(span, err))?;
self.unhandled_panic = Some((unhandled_panic, span));
Ok(())
}
fn macro_name(&self) -> &'static str {
if self.is_test {
"dbt_runtime::test"
} else {
"dbt_runtime::main"
}View on GitHub (pinned to 0267ce9170)
Solutions
- Keep a single `unhandled_panic = "..."` key
- Pick one behavior: `ignore` or `shutdown_runtime`
- Remove the option to accept the default behavior
Example fix
// before
#[tokio::test(unhandled_panic = "ignore", unhandled_panic = "shutdown_runtime")]
async fn t() {}
// after
#[tokio::test(unhandled_panic = "shutdown_runtime")]
async fn t() {} Defensive patterns
Strategy: validation
Validate before calling
fn check_no_dupes(attr_src: &str, key: &str) -> Result<(), String> {
let n = attr_src.matches(&format!("{} =", key)).count();
if n <= 1 { Ok(()) } else { Err(format!("duplicate `{key}`")) }
} Prevention
- Only add unhandled_panic when you have a specific reason; default is usually fine
- Don't copy test attributes between tests blindly — dedupe keys after pasting
- Keep one behavior choice documented per test suite
When it happens
Trigger: #[tokio::test(flavor = "current_thread", unhandled_panic = "ignore", unhandled_panic = "shutdown_runtime")] — duplicate `unhandled_panic` key in the attribute.
Common situations: Refactoring test attributes and leaving the old value in place; generators emitting the option twice; merging two tests' attribute lines.
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
- `worker_threads` set multiple times.
- `start_paused` set multiple times.
- `crate` 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/303fcfcb18f08a6b.
Report an issue: GitHub.