AdguardTeam/AdGuardHome · critical

reading cert file: %w

Error message

reading cert file: %w

What it means

The manager could not read the TLS certificate file from disk while loading the TLS configuration. It wraps an os.ReadFile failure such as ENOENT or EACCES on the configured CertificatePath.

Source

Thrown at internal/aghtls/defaultmanager.go:651

	}

	return certErr
}

// loadCertificateChainData loads PEM-encoded certificates chain data to the
// TLS configuration. tlsConf must be not nil. tlsConf.CertificateChainData
// struct field will be modified in case tlsConfig.CertificatePath is not an
// empty string.  extTLSConf must not be nil.
func loadCertificateChainData(extTLSConf *ExtendedTLSConfig) (err error) {
	extTLSConf.CertificateChainData = []byte(extTLSConf.CertificateChain)
	if extTLSConf.CertificatePath != "" {
		if extTLSConf.CertificateChain != "" {
			return errors.Error("certificate data and file can't be set together")
		}

		extTLSConf.CertificateChainData, err = os.ReadFile(extTLSConf.CertificatePath)
		if err != nil {
			return fmt.Errorf("reading cert file: %w", err)
		}
	}

	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)

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Verify the file exists and is readable: ls -l /path/to/cert.pem and run as a user with read access
  2. If certs are provisioned asynchronously, delay startup or retry LoadTLSConfig until the file appears
  3. Fix the configured path to point to the actual certificate file (not a directory)
  4. In containers, check the volume mount maps the file correctly

Example fix

// before
certificate_path: /etc/ssl/certs # directory, not the cert
// after
certificate_path: /etc/ssl/certs/example.com.fullchain.pem
Defensive patterns

Strategy: validation

Validate before calling

if info, err := os.Stat(conf.CertificatePath); err != nil || info.IsDir() {
    return fmt.Errorf("certificate path invalid: %s", conf.CertificatePath)
}

Try / catch

if err := mgr.LoadTLSConfig(ctx, conf); err != nil {
    if errors.Is(err, fs.ErrNotExist) { /* provision cert, retry */ }
}

Prevention

When it happens

Trigger: LoadTLSConfig with a CertificatePath that does not exist, is a directory, or lacks read permission for the process. Also triggered if both CertificateChain data and CertificatePath are set (guarded by a preceding error) or the file disappears between config and read.

Common situations: Wrong path in config (missing /etc/adguardhome or volume mount); cert file not yet provisioned by cert-manager/acme at startup; Docker bind-mount with wrong ownership; path with a typo.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/823ab693a2c6b90b. Report an issue: GitHub.