gofiber/fiber · critical

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

Error message

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

What it means

Returned by App.Listen when tls.LoadX509KeyPair fails to load the TLS certificate and private key pair. This happens at server startup when both Config.CertFile and Config.CertKeyFile are set but the files are missing, unreadable, or do not form a valid X.509 key pair. The error includes both file paths and the underlying tls error.

Source

Thrown at listen.go:214

//	app.Listen(":8080")
//	app.Listen("127.0.0.1:8080")
//	app.Listen(":8080", ListenConfig{EnablePrefork: true})
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()
	} else {
		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 9a4c7e57fe)

Solutions

  1. Verify both paths exist and are readable: ls -l cert.pem key.pem.
  2. Confirm cert and key match using openssl to compare the modulus of the cert and key.
  3. Use absolute paths for the cert and key files in production.
  4. Ensure PEM formatting (BEGIN/END CERTIFICATE and BEGIN/END PRIVATE KEY).
  5. For auto-rotating certs, prefer AutoCertManager or a custom TLSConfig with GetCertificate.

Example fix

// before
app.Listen(":443", fiber.ListenConfig{
    CertFile:    "cert",     // wrong/missing file
    CertKeyFile: "key",
})

// after
app.Listen(":443", fiber.ListenConfig{
    CertFile:    "/etc/tls/fullchain.pem",
    CertKeyFile: "/etc/tls/privkey.pem",
})
Defensive patterns

Strategy: validation

Validate before calling

// Validate the cert/key pair at startup before Listen
if _, err := tls.LoadX509KeyPair(certFile, keyFile); err != nil {
    log.Fatalf("invalid TLS key pair: %v", err)
}

Try / catch

if err := app.Listen(":443", fiber.ListenConfig{
    CertFile: certFile, CertKeyFile: keyFile,
}); err != nil {
    log.Fatalf("server stopped: %v", err)
}

Prevention

When it happens

Trigger: Calling app.Listen(":443", fiber.ListenConfig{CertFile: "cert.pem", CertKeyFile: "key.pem"}) where either file is missing, the key doesn't match the cert, the files are not PEM-encoded, or the process lacks read permission.

Common situations: Cert files not mounted into the container, paths relative to the wrong working directory, an expired/regenerated cert whose key wasn't updated in tandem, or permission issues on the secrets.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/4a30b810daaf678e.json. Report an issue: GitHub.