ory/hydra · error
unable to load X509 key pair from files: %v
Error message
unable to load X509 key pair from files: %v
What it means
Certificate resolves TLS material from paths or base64 strings. When both a cert path and key path are provided, it calls tls.LoadX509KeyPair; this error wraps any failure reading or parsing those files — missing files, permission denied, or invalid/unmatched PEM contents.
Source
Thrown at oryx/tlsx/cert.go:118
certPEMBase64, keyPEMBase64 string,
certPath, keyPath string,
) ([]tls.Certificate, error) {
if certPEMBase64 == "" && keyPEMBase64 == "" && certPath == "" && keyPath == "" {
return nil, errors.WithStack(ErrNoCertificatesConfigured)
}
if certPEMBase64 != "" && keyPEMBase64 != "" {
cert, err := CertificateFromBase64(certPEMBase64, keyPEMBase64)
if err != nil {
return nil, errors.WithStack(err)
}
return []tls.Certificate{cert}, nil
}
if certPath != "" && keyPath != "" {
cert, err := tls.LoadX509KeyPair(certPath, keyPath)
if err != nil {
return nil, fmt.Errorf("unable to load X509 key pair from files: %v", err)
}
return []tls.Certificate{cert}, nil
}
return nil, errors.WithStack(ErrInvalidCertificateConfiguration)
}
type CertFunc = func(*tls.ClientHelloInfo) (*tls.Certificate, error)
// GetCertificate returns a function for use with
// "net/tls".Config.GetCertificate.
//
// The certificate and private key are read from the specified filesystem paths.
// The certificate file is watched for changes, upon which the cert+key are
// reloaded in the background. Errors during reloading are deduplicated and
// reported through the errs channel if it is not nil. When the provided context
// is canceled, background reloading stops and the errs channel is closed.
//View on GitHub (pinned to 4174065ffb)
Solutions
- Verify both files exist and are readable by the process (ls -l, check mount/secret volume)
- Convert files to PEM format if they are DER (openssl x509 -inform der -outform pem)
- Ensure cert and key are a matching pair (compare moduli with openssl)
- Use absolute paths or set the correct working directory; re-check config/env values
Example fix
// before
cert, err := Certificate("/etc/ssl/cert.der", "/etc/ssl/key.pem", "", "")
// after (convert DER to PEM first)
// openssl x509 -inform der -in cert.der -out cert.pem
cert, err := Certificate("/etc/ssl/cert.pem", "/etc/ssl/key.pem", "", "") Defensive patterns
Strategy: validation
Validate before calling
func checkCertFiles(certPath, keyPath string) error {
for _, p := range []string{certPath, keyPath} {
if fi, err := os.Stat(p); err != nil || fi.IsDir() {
return fmt.Errorf("missing/unreadable %s", p)
}
}
_, err := tls.LoadX509KeyPair(certPath, keyPath)
return err
} Try / catch
certs, err := tlsx.Certificate(certPath, keyPath, "", "")
if err != nil && strings.Contains(err.Error(), "X509 key pair from files") {
log.WithError(err).Errorf("check paths %q / %q exist, are PEM, and form a matching pair", certPath, keyPath)
return err
} Prevention
- Mount secrets read-only and verify with a startup readiness check
- Use absolute paths; confirm the process working directory
- Keep cert/key files PEM and matched (renew both together)
When it happens
Trigger: Calling Certificate with non-empty certPath and keyPath where the files do not exist, are unreadable, contain non-PEM data, or the key does not match the certificate.
Common situations: Wrong paths in config (relative path vs working directory), container missing the mounted secret, permissions after secret rotation, DER instead of PEM, or cert/key pair mismatch after cert renewal.
Related errors
- unable to load X509 key pair: %v
- unable to base64 decode the TLS certificate: %v
- failed to create certificate: %s
- failed to encode private key: %s
- the CA certificate does not have the client authentication e
AI-assisted analysis of ory/hydra@4174065ffb (2026-09-03).
Data as JSON: /api/errors/a405aa8d1b221588.
Report an issue: GitHub.