AdguardTeam/AdGuardHome · error
opening dnscrypt config: %w
Error message
opening dnscrypt config: %w
What it means
The DNSCrypt resolver configuration file could not be opened. os.Open on DNSCryptConfigFile failed; the wrapped error is typically 'no such file or directory' or 'permission denied'.
Source
Thrown at internal/home/dns.go:380
}
// newDNSCryptConfig converts values from the configuration file into the
// internal DNSCrypt settings for the DNS server. extTLSConf must not be nil.
func newDNSCryptConfig(
extTLSConf *aghtls.ExtendedTLSConfig,
addrs []netip.Addr,
) (dnsCryptConf *dnsforward.DNSCryptConfig, err error) {
if extTLSConf.PortDNSCrypt == 0 {
return nil, nil
}
if extTLSConf.DNSCryptConfigFile == "" {
return nil, fmt.Errorf("dnscrypt_config_file: %w", errors.ErrEmptyValue)
}
f, err := os.Open(extTLSConf.DNSCryptConfigFile)
if err != nil {
return nil, fmt.Errorf("opening dnscrypt config: %w", err)
}
defer func() { err = errors.WithDeferred(err, f.Close()) }()
rc := &dnscrypt.ResolverConfig{}
err = yaml.NewDecoder(f).Decode(rc)
if err != nil {
return nil, fmt.Errorf("decoding dnscrypt config: %w", err)
}
cert, err := rc.NewCert()
if err != nil {
return nil, fmt.Errorf("creating dnscrypt cert: %w", err)
}
return &dnsforward.DNSCryptConfig{
ResolverCert: cert,
UDPListenAddrs: ipsToUDPAddrs(addrs, extTLSConf.PortDNSCrypt),
TCPListenAddrs: ipsToTCPAddrs(addrs, extTLSConf.PortDNSCrypt),View on GitHub (pinned to b41aefbe51)
Solutions
- Confirm the file exists at the exact configured path: ls -l <path>
- Fix ownership/permissions so the service user can read it (chmod 644 or chown)
- Correct the dnscrypt_config_file value in config.yaml
- In containers, verify the volume mount actually exposes the file
Example fix
# before tls: dnscrypt_config_file: /etc/adguard/dnscrypt.yaml # file not present # after sudo cp ~/dnscrypt.yaml /etc/adguard/dnscrypt.yaml sudo chmod 644 /etc/adguard/dnscrypt.yaml tls: dnscrypt_config_file: /etc/adguard/dnscrypt.yaml
Defensive patterns
Strategy: validation
Validate before calling
if _, err := os.Stat(tlsConf.DNSCryptConfigFile); err != nil {
return fmt.Errorf("dnscrypt config file %q: %w", tlsConf.DNSCryptConfigFile, err)
} Type guard
func fileReadable(p string) bool {
f, err := os.Open(p)
if err != nil { return false }
f.Close()
return true
} Try / catch
if err != nil {
if errors.Is(err, fs.ErrNotExist) {
log.Error("dnscrypt config missing; recreating from template")
} else if errors.Is(err, fs.ErrPermission) {
log.Error("fix permissions on dnscrypt config")
}
} Prevention
- Use absolute paths for dnscrypt_config_file
- In Docker, mount the dnscrypt config as a volume and verify inside the container
- Back up the file alongside config.yaml during upgrades
When it happens
Trigger: dnscrypt_config_file pointing to a non-existent path, or a path the AdGuard Home process user cannot read (wrong permissions, SELinux denial, container volume not mounted).
Common situations: Typo'd path in config.yaml, file deleted or moved during upgrade, running in Docker without mounting the file, restrictive ownership (e.g. root-owned 600 file read by an unprivileged service user).
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- dnscrypt_config_file: %w
- decoding dnscrypt config: %w
- creating dnscrypt cert: %w
- init querylog: %w
- creating dns server: %w
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/9810de25a557a405.
Report an issue: GitHub.