gofiber/fiber · critical

failed to append certificate

Error message

failed to append certificate

What it means

Wraps the failure returned by tls.Config.RootCAs.AppendCertsFromPEM inside Client.SetRootCertificate (client/client.go:336) and SetRootCertificateFromString (client/client.go:351). AppendCertsFromPEM returns false when the PEM bytes contain no parseable certificate blocks; Fiber turns that into a logger.Panicf, terminating the program because client configuration is unrecoverable.

Solutions

  1. Verify the file is PEM-encoded: it must have '-----BEGIN CERTIFICATE-----' / '-----END CERTIFICATE-----' blocks. Convert DER with: openssl x509 -inform DER -in cert.der -out cert.pem -outform PEM.
  2. Inspect the file before passing it; ensure at least one CERTIFICATE block is present.
  3. Load and AppendCertsFromPEM in your own code first to get a real error rather than the panic, then assign tls.Config directly.
  4. If you must keep the panic behavior, gate the call behind a build/runtime check so misconfiguration surfaces at startup, not mid-request.

Example fix

// before
client.SetRootCertificate("/etc/secrets/ca.der") // ErrFailedToAppendCert panic

// after
// convert once: openssl x509 -inform DER -in ca.der -out ca.pem -outform PEM
client.SetRootCertificate("/etc/secrets/ca.pem")
Defensive patterns

Strategy: validation

Validate before calling

// Validate the PEM in your own code to get a real error before the panic
func mustAppendCAs(pool *x509.CertPool, pem []byte) error {
    if !pool.AppendCertsFromPEM(pem) {
        return errors.New("PEM contained no parseable certificate")
    }
    return nil
}
// call this before client.SetRootCertificateFromString(string(pem))

Type guard

func looksLikePEMCert(pem []byte) bool {
    return bytes.Contains(pem, []byte("-----BEGIN CERTIFICATE-----")) &&
        bytes.Contains(pem, []byte("-----END CERTIFICATE-----"))
}

Try / catch

// SetRootCertificate panics, so wrap setup in recover if you want graceful failure:
func safeSetRootCert(c *fiber.Client, path string) (err error) {
    defer func() {
        if r := recover(); r != nil { err = fmt.Errorf("%v", r) }
    }()
    c.SetRootCertificate(path)
    return nil
}

Prevention

When it happens

Trigger: Calling client.SetRootCertificate(path) where the file is not valid PEM, contains only a private key, has a corrupted BEGIN/END block, or is empty; calling SetRootCertificateFromString(pem) with the contents of a CSR, a DER blob, or a typo-pasted bundle.

Common situations: Pointing SetRootCertificate at a certificate in DER instead of PEM format; passing a fullchain that includes non-certificate sections; copy/paste truncating the END line; reading a key file by mistake.

Understand the failure class

Related errors


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

Appendix: source

Thrown at client/client.go:34

	"io"
	"os"
	"path/filepath"
	"slices"
	"sync"
	"sync/atomic"
	"time"

	"github.com/fxamacker/cbor/v2"
	"github.com/gofiber/fiber/v3/log"

	"github.com/gofiber/utils/v2"

	"github.com/valyala/fasthttp"
	"github.com/valyala/fasthttp/fasthttpproxy"
	"golang.org/x/net/http/httpproxy"
)

var ErrFailedToAppendCert = errors.New("failed to append certificate")

// Client provides Fiber's high-level HTTP API while delegating transport work
// to fasthttp.Client, fasthttp.HostClient, or fasthttp.LBClient implementations.
//
// Settings configured on the client are shared across every request and may be
// overridden per request when needed.
// Client is safe for concurrent request execution after configuration is
// complete. Concurrent configuration changes require external synchronization.
type Client struct {
	logger    log.CommonLogger
	transport httpClientTransport

	header  *Header
	params  *QueryParam
	cookies *Cookie
	path    *PathParam

	jsonMarshal   utils.JSONMarshal

View on GitHub (pinned to a105acad6c)