{"record":{"id":"5992f8b1eee2e87d","repo":"stalwartlabs/stalwart","slug":"failed-to-build-dns-resolver","errorCode":null,"errorMessage":"Failed to build DNS resolver","messagePattern":"Failed to build DNS resolver","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/common/src/config/smtp/resolver.rs","lineNumber":348,"sourceCode":"    }\n}\n\nimpl Default for Resolvers {\n    fn default() -> Self {\n        let (config, opts) = match read_system_conf() {\n            Ok(conf) => conf,\n            Err(_) => (\n                ResolverConfig::udp_and_tcp(&CLOUDFLARE),\n                ResolverOpts::default(),\n            ),\n        };\n\n        let config_dnssec = config.clone();\n        let mut opts_dnssec = opts.clone();\n        opts_dnssec.validate = true;\n\n        Self {\n            dns: MessageAuthenticator::new(config, opts).expect(\"Failed to build DNS resolver\"),\n            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            dnssec_available: true,\n        }\n    }\n}\n\nimpl Display for Policy {\n    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {\n        f.write_str(\"version: STSv1\\r\\n\")?;\n        f.write_str(\"mode: \")?;","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/stalwartlabs/stalwart/blob/e96200385781a6a9995a8b839ac27d6c75a983ee/crates/common/src/config/smtp/resolver.rs#L330-L366","documentation":"This panic occurs when the standard (non-DNSSEC) hickory resolver wrapped in MessageAuthenticator cannot be built during resolver initialization. MessageAuthenticator::new(config, opts) uses .expect(\"Failed to build DNS resolver\"), so any invalid resolver configuration aborts instead of returning an error. It indicates the ResolverConfig or ResolverOpts supplied for plain DNS are invalid.","triggerScenarios":"Constructing the resolver struct where MessageAuthenticator::new(config, opts) fails — a ResolverConfig with malformed nameserver addresses/ports, or ResolverOpts values hickory rejects at build time (invalid timeouts, cache sizes, or protocol settings).","commonSituations":"Typo'd or malformed nameserver IP in the smtp.resolver config section; invalid resolver options (protocol, timeout, cache) in configuration; hickory version upgrades changing accepted option semantics; corrupted config values loaded from TOML.","solutions":["Validate the nameserver IPs/ports and resolver options in the smtp.resolver config section","Revert to default resolver options (remove custom timeout/cache/protocol overrides) to isolate the offending value","Test resolution with a minimal config using system resolvers","Check hickory-resolver changelogs after upgrades for option semantics changes","Replace .expect() with proper error propagation so startup reports the underlying cause"],"exampleFix":"// before\nMessageAuthenticator::new(config, opts).expect(\"Failed to build DNS resolver\"),\n// after\nMessageAuthenticator::new(config, opts)\n    .map_err(|e| anyhow!(\"Failed to build DNS resolver: {e}\"))?,","handlingStrategy":"validation","validationCode":"// sanity-check the plain DNS config before constructing the resolver\nfn validate_dns_options(opts: &ResolverOpts) -> Result<(), String> {\n    if opts.timeout.is_zero() {\n        return Err(\"resolver timeout must be > 0\".into());\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"// The constructor panics via expect; guard at startup:\nlet resolvers = std::panic::catch_unwind(|| build_resolvers(&config, &opts))\n    .map_err(|_| anyhow!(\"DNS resolver init panicked — check resolver config\"))?;","preventionTips":["Double-check nameserver addresses and ports in the resolver config for typos","Avoid exotic ResolverOpts overrides unless documented for your hickory version","Validate all TOML config values that feed into ResolverConfig/ResolverOpts","Run a config self-test at startup that resolves a known name before serving traffic"],"tags":["dns","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"}