gohugoio/hugo · error

failed to verify certificate

Error message

failed to verify certificate: %v

What it means

`verifyCert` runs Go's `x509.Certificate.Verify` against the root pool and the requested hostname (`DNSName`). This wraps the verification failure, meaning the cert does not chain to the trusted root and/or the hostname/SAN does not match. `%v` is Go's verify error.

Solutions

  1. Delete the cached `_mkcerts/<hostname>.pem` and key so Hugo reissues for the current hostname.
  2. Ensure `$CAROOT` points at the same root CA that signed the site cert.
  3. Confirm the requested hostname matches a SAN in the cert (use `openssl x509 -text`).
  4. Re-run `mkcert -install` to make sure the root is trusted system-wide.

Example fix

// before
// baseURL changed to https://myapp.test/ but cached cert is for localhost
// after
// rm -rf $cachedir/_mkcerts && hugo server --tlsAuto --baseURL=https://myapp.test/
Defensive patterns

Strategy: validation

Validate before calling

import "crypto/x509"
func validateCertForHost(certPEM, rootPEM []byte, host string) error {
  roots := x509.NewCertPool()
  if !roots.AppendCertsFromPEM(rootPEM) { return fmt.Errorf("bad root") }
  block, _ := pem.Decode(certPEM)
  if block == nil { return fmt.Errorf("bad cert PEM") }
  cert, err := x509.ParseCertificate(block.Bytes)
  if err != nil { return err }
  opts := x509.VerifyOptions{DNSName: host, Roots: roots}
  _, err = cert.Verify(opts)
  return err
}

Type guard

null

Try / catch

// If verify fails after a hostname change, reissue for the new host.
if _, err := cert.Verify(opts); err != nil {
  os.Remove(certFile); os.Remove(keyFile)
  // next start provisions certs for the current hostname
}

Prevention

When it happens

Trigger: Fires when the cached site cert was issued for a different hostname than the current `baseURL` hostname, the root CA differs from the one that signed it, or the cert has expired.

Common situations: Changing the server `baseURL`/hostname after generating certs (cert was for `localhost`, now serving `mysite.test`); a regenerated mkcert root CA invalidating older site certs; an expired cached cert.

Understand the failure class

Related errors


AI-assisted analysis of gohugoio/hugo@52c9bd7908 (2026-08-09). Data as JSON: /api/errors/045aabd313b0ca87. Report an issue: GitHub.

Appendix: source

Thrown at commands/server.go:747

		return fmt.Errorf("failed to parse root certificate")
	}

	block, _ := pem.Decode(certPEM)
	if block == nil {
		return fmt.Errorf("failed to parse certificate PEM")
	}
	cert, err := x509.ParseCertificate(block.Bytes)
	if err != nil {
		return fmt.Errorf("failed to parse certificate: %v", err.Error())
	}

	opts := x509.VerifyOptions{
		DNSName: name,
		Roots:   roots,
	}

	if _, err := cert.Verify(opts); err != nil {
		return fmt.Errorf("failed to verify certificate: %v", err.Error())
	}

	return nil
}

func (c *serverCommand) createServerPorts(cd *simplecobra.Commandeer) error {
	flags := cd.CobraCommand.Flags()
	var cerr error
	c.withConf(func(conf *commonConfig) {
		isMultihost := conf.configs.IsMultihost
		c.serverPorts = make([]serverPortListener, 1)
		if isMultihost {
			if !c.serverAppend {
				cerr = errors.New("--appendPort=false not supported when in multihost mode")
				return
			}
			c.serverPorts = make([]serverPortListener, len(conf.configs.Languages))
		}

View on GitHub (pinned to 52c9bd7908)