AdguardTeam/AdGuardHome · critical
reading key file: %w
Error message
reading key file: %w
What it means
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.
Source
Thrown at internal/aghtls/defaultmanager.go:671
}
return nil
}
// loadPrivateKeyData loads PEM-encoded private key data to the TLS
// configuration. tlsConf must be not nil. tlsConf.PrivateKeyData struct field
// will be modified in case tlsConfig.PrivateKeyPath is not an empty string.
// extTLSConf must not be nil.
func loadPrivateKeyData(extTLSConf *ExtendedTLSConfig) (err error) {
extTLSConf.PrivateKeyData = []byte(extTLSConf.PrivateKey)
if extTLSConf.PrivateKeyPath != "" {
if extTLSConf.PrivateKey != "" {
return errors.Error("private key data and file can't be set together")
}
extTLSConf.PrivateKeyData, err = os.ReadFile(extTLSConf.PrivateKeyPath)
if err != nil {
return fmt.Errorf("reading key file: %w", err)
}
}
return nil
}
// validateCertChain verifies certs using the first as the main one and others
// as intermediate. srvName stands for the expected DNS name. certs must not
// be empty. logger must not be nil.
func validateCertChain(
ctx context.Context,
logger *slog.Logger,
rootCAs *x509.CertPool,
certs []*x509.Certificate,
srvName string,
) (err error) {
main, others := certs[0], certs[1:]
View on GitHub (pinned to b41aefbe51)
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
Example fix
// before private_key_path: /etc/ssl/certs/example.com.pem # actually the cert // after private_key_path: /etc/ssl/private/example.com.key
Defensive patterns
Strategy: validation
Validate before calling
if info, err := os.Stat(conf.PrivateKeyPath); err != nil || info.IsDir() {
return fmt.Errorf("key path invalid: %s", conf.PrivateKeyPath)
} Try / catch
if err := mgr.LoadTLSConfig(ctx, conf); err != nil {
if errors.Is(err, fs.ErrPermission) { /* fix ownership; do not run as root long-term */ }
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- reading cert file: %w
- networksetup failed to configure dns servers: %w
- watching %s %s: %w
- reading db: %w
- writing new config: %w
AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27).
Data as JSON: /api/errors/f891d9b93ce5cbdc.
Report an issue: GitHub.