gofiber/fiber · critical

tls: cannot load TLS key pair from certFile=

Error message

tls: cannot load TLS key pair from certFile=%q and keyFile=%q: %w

What it means

Returned by App.Listen / ListenTLS at startup when tls.LoadX509KeyPair fails to load the configured CertFile and CertKeyFile. The error wraps the cert and key paths and the underlying crypto/tls error: 'tls: cannot load TLS key pair from certFile="server.crt" and keyFile="server.key": open server.crt: no such file or directory'. Fires only when both CertFile and CertKeyFile are set and TLSConfig is nil (the manual-cert branch at listen.go:227).

Solutions

  1. Verify both files exist and are readable by the process uid; log their absolute paths at startup.
  2. Confirm the key file is PEM-encoded (BEGIN PRIVATE KEY / BEGIN RSA PRIVATE KEY / BEGIN EC PRIVATE KEY) and matches the cert's public key.
  3. Use absolute paths or resolve them from a known root; in containers, mount certs from a secret and reference the mount path.
  4. Validate the pair in isolation with tls.LoadX509KeyPair in a tiny program or a startup self-check before Listen.

Example fix

// before
app.ListenTLS(":443", "server.crt", "server.key") // paths wrong / unreadable

// after
if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil {
    log.Fatalf("cert check failed: %v", err)
}
app.ListenTLS(":443", certPath, keyPath)
Defensive patterns

Strategy: validation

Validate before calling

// preflight: load and validate the cert/key pair before Listen
if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
    log.Fatalf("invalid TLS key pair: %v", err)
}
if _, err := os.Stat(certFile); err != nil { log.Fatal(err) }
if _, err := os.Stat(keyFile); err != nil { log.Fatal(err) }

Type guard

null

Try / catch

if err := app.ListenTLS(":443", certFile, keyFile); err != nil {
    if strings.Contains(err.Error(), "cannot load TLS key pair") {
        log.Fatalf("TLS cert/key invalid: %v", err)
    }
    log.Fatal(err)
}

Prevention

When it happens

Trigger: Calling app.ListenTLS(...) or app.Listen(addr, WithTLS(cert, key)) where the cert or key file cannot be read or is not a valid PEM-encoded X.509 key pair. AutoCertManager being set with cert files returns a different error (ErrAutoCertWithCertFile) earlier.

Common situations: Wrong paths (relative path resolved against cwd, not source), cert/key not mounted into the container, permissions on the key file, PEM block missing or wrong type (e.g. cert file contains only the chain without the leaf, key file is PKCS#12 instead of PEM), expired/rotated cert files replaced incompletely, or cert and key swapped.

Understand the failure class

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/4a30b810daaf678e. Report an issue: GitHub.

Appendix: source

Thrown at listen.go:230

func (app *App) Listen(addr string, config ...ListenConfig) error {
	cfg := listenConfigDefault(config...)

	// Configure TLS
	var tlsConfig *tls.Config
	var tlsHandler *TLSHandler
	if cfg.TLSConfig != nil {
		tlsConfig = cfg.TLSConfig.Clone()
		warnSupersededTLSFields(&cfg)
	} else {
		validateTLSMinVersion(&cfg)

		switch {
		case cfg.AutoCertManager != nil && (cfg.CertFile != "" || cfg.CertKeyFile != ""):
			return ErrAutoCertWithCertFile
		case cfg.CertFile != "" && cfg.CertKeyFile != "":
			cert, err := tls.LoadX509KeyPair(cfg.CertFile, cfg.CertKeyFile)
			if err != nil {
				return fmt.Errorf("tls: cannot load TLS key pair from certFile=%q and keyFile=%q: %w", cfg.CertFile, cfg.CertKeyFile, err)
			}

			tlsHandler = &TLSHandler{}
			tlsConfig = &tls.Config{
				MinVersion: cfg.TLSMinVersion,
				Certificates: []tls.Certificate{
					cert,
				},
				GetCertificate: tlsHandler.GetClientInfo,
			}

		case cfg.AutoCertManager != nil:
			tlsConfig = &tls.Config{
				MinVersion:     cfg.TLSMinVersion,
				GetCertificate: cfg.AutoCertManager.GetCertificate,
				NextProtos:     []string{"http/1.1", "acme-tls/1"},
			}
		default:

View on GitHub (pinned to a105acad6c)