{"record":{"id":"f891d9b93ce5cbdc","repo":"AdguardTeam/AdGuardHome","slug":"reading-key-file-w","errorCode":null,"errorMessage":"reading key file: %w","messagePattern":"reading key file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/aghtls/defaultmanager.go","lineNumber":671,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// loadPrivateKeyData loads PEM-encoded private key data to the TLS\n// configuration. tlsConf must be not nil. tlsConf.PrivateKeyData struct field\n// will be modified in case tlsConfig.PrivateKeyPath is not an empty string.\n// extTLSConf must not be nil.\nfunc loadPrivateKeyData(extTLSConf *ExtendedTLSConfig) (err error) {\n\textTLSConf.PrivateKeyData = []byte(extTLSConf.PrivateKey)\n\tif extTLSConf.PrivateKeyPath != \"\" {\n\t\tif extTLSConf.PrivateKey != \"\" {\n\t\t\treturn errors.Error(\"private key data and file can't be set together\")\n\t\t}\n\n\t\textTLSConf.PrivateKeyData, err = os.ReadFile(extTLSConf.PrivateKeyPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading key file: %w\", err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// validateCertChain verifies certs using the first as the main one and others\n// as intermediate.  srvName stands for the expected DNS name.  certs must not\n// be empty.  logger must not be nil.\nfunc validateCertChain(\n\tctx context.Context,\n\tlogger *slog.Logger,\n\trootCAs *x509.CertPool,\n\tcerts []*x509.Certificate,\n\tsrvName string,\n) (err error) {\n\tmain, others := certs[0], certs[1:]\n","sourceCodeStart":653,"sourceCodeEnd":689,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/aghtls/defaultmanager.go#L653-L689","documentation":"The manager could not read the TLS private key file from disk while loading TLS configuration. It wraps an os.ReadFile failure (ENOENT, EACCES, etc.) on the configured PrivateKeyPath.","triggerScenarios":"LoadTLSConfig with a PrivateKeyPath that is missing, unreadable due to permissions (common: root-owned 600 key read by non-root process), or set while PrivateKey data is also provided (preceding guard error).","commonSituations":"Key file permission mismatch when running the service as an unprivileged user; key provisioned later than startup; mismatched path (key vs cert swapped); both inline PrivateKey and PrivateKeyPath configured.","solutions":["Check existence and permissions of the key file; ensure the service user can read it (often needs group-read with restricted group)","Align provisioning so the key exists before the service starts","Remove the inline PrivateKey if using PrivateKeyPath (they are mutually exclusive)","Confirm PrivateKeyPath points to the key, not the certificate"],"exampleFix":"// before\nprivate_key_path: /etc/ssl/certs/example.com.pem # actually the cert\n// after\nprivate_key_path: /etc/ssl/private/example.com.key","handlingStrategy":"validation","validationCode":"if info, err := os.Stat(conf.PrivateKeyPath); err != nil || info.IsDir() {\n    return fmt.Errorf(\"key path invalid: %s\", conf.PrivateKeyPath)\n}","typeGuard":null,"tryCatchPattern":"if err := mgr.LoadTLSConfig(ctx, conf); err != nil {\n    if errors.Is(err, fs.ErrPermission) { /* fix ownership; do not run as root long-term */ }\n}","preventionTips":["Never set both PrivateKey and PrivateKeyPath","Grant the service user read access to the key via group permissions","Verify paths in a pre-start health check"],"tags":["tls","filesystem","permissions","configuration"],"backgroundTag":"private-key-file-not-found","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}