ory/hydra · error
failed to encode private key: %s
Error message
failed to encode private key: %s
What it means
After successfully creating the DER-encoded certificate, CreateSelfSignedCertificate parses it back with x509.ParseCertificate to return an *x509.Certificate. If that parse fails, it returns this error (whose wording — 'failed to encode private key' — is misleading; it actually means the freshly generated certificate could not be parsed). In practice this is nearly impossible unless the crypto/x509 implementation is broken or a CertificateOpts produced a malformed template.
Source
Thrown at oryx/tlsx/cert.go:284
NotAfter: time.Now().UTC().Add(time.Hour * 24 * 31),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
IsCA: true,
DNSNames: []string{"localhost"},
}
for _, opt := range opts {
opt(certificate)
}
der, err := x509.CreateCertificate(rand.Reader, certificate, certificate, PublicKey(key), key)
if err != nil {
return cert, errors.Errorf("failed to create certificate: %s", err)
}
cert, err = x509.ParseCertificate(der)
if err != nil {
return cert, errors.Errorf("failed to encode private key: %s", err)
}
return cert, nil
}
// PEMBlockForKey returns a PEM-encoded block for key.
func PEMBlockForKey(key interface{}) (*pem.Block, error) {
b, err := x509.MarshalPKCS8PrivateKey(key)
if err != nil {
return nil, errors.WithStack(err)
}
return &pem.Block{Type: "PRIVATE KEY", Bytes: b}, nil
}
// NewClientCert creates a new client TLS certificate signed by the given CA.
func NewClientCert(CAcert *x509.Certificate, CAkey crypto.PrivateKey, opts ...CertificateOpts) (*tls.Certificate, error) {
if !slices.Contains(CAcert.ExtKeyUsage, x509.ExtKeyUsageClientAuth) {
return nil, errors.Errorf("the CA certificate does not have the client authentication extended key usage (OID 1.3.6.1.5.5.7.3.2) set")
}View on GitHub (pinned to 4174065ffb)
Solutions
- Review any custom CertificateOpts functions for values that produce invalid certificate fields (e.g. bad extensions, invalid validity ranges).
- Retry the generation — transient crypto-stack failures resolve on re-run.
- Update the Go toolchain/runtime to a current patch version to rule out a crypto/x509 bug.
Example fix
// before opt(certificate) // sets NotBefore after NotAfter // after opt(certificate) // ensure opts keep NotBefore < NotAfter and valid fields
Defensive patterns
Strategy: try-catch
Validate before calling
// Verify custom opts keep fields valid: // c.NotBefore.Before(c.NotAfter), no duplicate extensions, valid DNS names.
Try / catch
cert, err := tlsx.CreateSelfSignedCertificate(key, opts...)
if err != nil && strings.Contains(err.Error(), "failed to encode private key") {
// misleading message: DER parse failed — audit opts, then retry once
} Prevention
- Audit custom CertificateOpts for fields that could yield an unparseable certificate.
- Keep NotBefore < NotAfter and use valid SANs/DNS names in opts.
- Pin a current Go patch release to rule out crypto/x509 regressions.
When it happens
Trigger: x509.ParseCertificate rejecting the DER bytes returned by x509.CreateCertificate — essentially only possible with a corrupted crypto stack or an exotic opts callback that produced an invalid certificate structure.
Common situations: Extremely rare; occasionally seen on platforms with patched/broken crypto libraries, or when a custom CertificateOpts injects invalid extensions the parser then rejects.
Related errors
- failed to create certificate: %s
- unable to load X509 key pair: %v
- unable to load X509 key pair from files: %v
- failed to generate serial number: %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/c5605673d0793ef5.
Report an issue: GitHub.