{"record":{"id":"876b003b27526e44","repo":"stalwartlabs/stalwart","slug":"failed-to-build-dnssec-resolver","errorCode":null,"errorMessage":"Failed to build DNSSEC resolver","messagePattern":"Failed to build DNSSEC resolver","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/common/src/config/smtp/resolver.rs","lineNumber":225,"sourceCode":"            }\n        }\n\n        // We already have a cache, so disable the built-in cache\n        opts.cache_size = 0;\n\n        // Prepare DNSSEC resolver options\n        let config_dnssec = resolver_config.clone();\n        let mut opts_dnssec = opts.clone();\n        opts_dnssec.validate = true;\n\n        let dnssec = DnssecResolver {\n            resolver: TokioResolver::builder_with_config(\n                config_dnssec,\n                TokioRuntimeProvider::default(),\n            )\n            .with_options(opts_dnssec)\n            .build()\n            .expect(\"Failed to build DNSSEC resolver\"),\n        };\n\n        Resolvers {\n            #[cfg(not(feature = \"test_mode\"))]\n            dnssec_available: ensure_dnssec(&resolver_config, &dnssec.resolver).await,\n            #[cfg(feature = \"test_mode\")]\n            dnssec_available: true,\n            dns: MessageAuthenticator::new(resolver_config, opts).unwrap(),\n            dnssec,\n        }\n    }\n}\n\n#[cfg(not(feature = \"test_mode\"))]\nasync fn ensure_dnssec(config: &ResolverConfig, resolver: &TokioResolver) -> bool {\n    config.name_servers().iter().any(|name_server| {\n        name_server\n            .connections","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/common/src/config/smtp/resolver.rs#L207-L243","documentation":"This panic occurs during resolver initialization when the DNSSEC-validating hickory (trust-dns) resolver cannot be built from the provided ResolverConfig and options. DnssecResolver::new calls .build().expect(...), so any builder failure aborts startup instead of returning a typed error. It means the DNSSEC resolver could not be constructed at all from the given configuration.","triggerScenarios":"Calling DnssecResolver::new (as part of Resolvers init) where TokioResolver::builder_with_config(config_dnssec, TokioRuntimeProvider::default()).with_options(opts_dnssec).build() returns an error — e.g. a ResolverConfig containing unparseable nameserver IPs or invalid DNSSEC options/trust anchors.","commonSituations":"smtp.resolver config with malformed nameserver IPs or ports; invalid custom DNSSEC trust-anchor/root key settings; hickory-resolver version incompatibility after dependency upgrades; platform/network init failures inside hickory.","solutions":["Check that the resolver nameserver IPs and ports in the SMTP resolver config are valid (dotted-quad, valid port)","Remove or fix any custom DNSSEC trust-anchor/root-key settings in the configuration","Test with default system resolvers to isolate whether the custom config is the cause","Verify hickory-resolver version compatibility after dependency upgrades","Replace .expect() with error propagation at the call site so the underlying builder error is reported instead of an opaque panic"],"exampleFix":"// before\n.build()\n.expect(\"Failed to build DNSSEC resolver\"),\n// after\n.build()\n.map_err(|e| anyhow!(\"Failed to build DNSSEC resolver: {e}\"))?,","handlingStrategy":"validation","validationCode":"// validate resolver config before init\nfn validate_resolver_config(cfg: &ResolverConfig) -> Result<(), String> {\n    for ns in cfg.name_servers() {\n        // skip_addr parses the IP:port of each nameserver\n        if ns.addr().is_unspecified() {\n            return Err(format!(\"invalid nameserver address: {}\", ns));\n        }\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"// .expect() panics; wrap process startup to surface the message:\nmatch resolvers_init(&config).await {\n    Ok(r) => r,\n    Err(e) => {\n        eprintln!(\"resolver init failed: {e}\");\n        std::process::exit(1);\n    }\n}","preventionTips":["Validate nameserver IPs/ports in smtp.resolver config before startup","Avoid custom DNSSEC trust anchors unless you can verify their format","Test resolver init with default system configuration as a baseline","Keep hickory-resolver versions aligned across the workspace after upgrades"],"tags":["dns","dnssec","panic","resolver","config"],"backgroundTag":"module-init-failed","analyzedSha":"e96200385781a6a9995a8b839ac27d6c75a983ee","analyzedAt":"2026-09-06T22:07:17.982Z","contentChangedAt":"2026-09-06T22:07:17.982Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}