{"record":{"id":"9810de25a557a405","repo":"AdguardTeam/AdGuardHome","slug":"opening-dnscrypt-config-w","errorCode":null,"errorMessage":"opening dnscrypt config: %w","messagePattern":"opening dnscrypt config: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/home/dns.go","lineNumber":380,"sourceCode":"}\n\n// newDNSCryptConfig converts values from the configuration file into the\n// internal DNSCrypt settings for the DNS server.  extTLSConf must not be nil.\nfunc newDNSCryptConfig(\n\textTLSConf *aghtls.ExtendedTLSConfig,\n\taddrs []netip.Addr,\n) (dnsCryptConf *dnsforward.DNSCryptConfig, err error) {\n\tif extTLSConf.PortDNSCrypt == 0 {\n\t\treturn nil, nil\n\t}\n\n\tif extTLSConf.DNSCryptConfigFile == \"\" {\n\t\treturn nil, fmt.Errorf(\"dnscrypt_config_file: %w\", errors.ErrEmptyValue)\n\t}\n\n\tf, err := os.Open(extTLSConf.DNSCryptConfigFile)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"opening dnscrypt config: %w\", err)\n\t}\n\tdefer func() { err = errors.WithDeferred(err, f.Close()) }()\n\n\trc := &dnscrypt.ResolverConfig{}\n\terr = yaml.NewDecoder(f).Decode(rc)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"decoding dnscrypt config: %w\", err)\n\t}\n\n\tcert, err := rc.NewCert()\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"creating dnscrypt cert: %w\", err)\n\t}\n\n\treturn &dnsforward.DNSCryptConfig{\n\t\tResolverCert:   cert,\n\t\tUDPListenAddrs: ipsToUDPAddrs(addrs, extTLSConf.PortDNSCrypt),\n\t\tTCPListenAddrs: ipsToTCPAddrs(addrs, extTLSConf.PortDNSCrypt),","sourceCodeStart":362,"sourceCodeEnd":398,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/home/dns.go#L362-L398","documentation":"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'.","triggerScenarios":"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).","commonSituations":"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).","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"],"exampleFix":"# before\ntls:\n  dnscrypt_config_file: /etc/adguard/dnscrypt.yaml   # file not present\n# after\nsudo cp ~/dnscrypt.yaml /etc/adguard/dnscrypt.yaml\nsudo chmod 644 /etc/adguard/dnscrypt.yaml\ntls:\n  dnscrypt_config_file: /etc/adguard/dnscrypt.yaml","handlingStrategy":"validation","validationCode":"if _, err := os.Stat(tlsConf.DNSCryptConfigFile); err != nil {\n    return fmt.Errorf(\"dnscrypt config file %q: %w\", tlsConf.DNSCryptConfigFile, err)\n}","typeGuard":"func fileReadable(p string) bool {\n    f, err := os.Open(p)\n    if err != nil { return false }\n    f.Close()\n    return true\n}","tryCatchPattern":"if err != nil {\n    if errors.Is(err, fs.ErrNotExist) {\n        log.Error(\"dnscrypt config missing; recreating from template\")\n    } else if errors.Is(err, fs.ErrPermission) {\n        log.Error(\"fix permissions on dnscrypt config\")\n    }\n}","preventionTips":["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"],"tags":["dns","adguard-home","dnscrypt","file-io","permissions"],"backgroundTag":"file-not-found","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}