golang-migrate/migrate · error

failed to append PEM

Error message

failed to append PEM

What it means

ErrAppendPEM is returned by mysql.urlToMySQLConfig when tls.Config.RootCAs.AppendCertsFromPEM fails: the PEM data read from the x-tls-ca file (or inline value) could not be parsed as any certificate. It signals malformed, empty, or wrong-format certificate material supplied for TLS verification of the MySQL server.

Source

Thrown at database/mysql/mysql.go:36

	"time"

	"github.com/go-sql-driver/mysql"
	"github.com/golang-migrate/migrate/v4/database"
)

var _ database.Driver = (*Mysql)(nil) // explicit compile time type check

func init() {
	database.Register("mysql", &Mysql{})
}

var DefaultMigrationsTable = "schema_migrations"

var (
	ErrDatabaseDirty    = fmt.Errorf("database is dirty")
	ErrNilConfig        = fmt.Errorf("no config")
	ErrNoDatabaseName   = fmt.Errorf("no database name")
	ErrAppendPEM        = fmt.Errorf("failed to append PEM")
	ErrTLSCertKeyConfig = fmt.Errorf("to use TLS client authentication, both x-tls-cert and x-tls-key must not be empty")
)

type Config struct {
	MigrationsTable  string
	DatabaseName     string
	NoLock           bool
	StatementTimeout time.Duration
}

type Mysql struct {
	// mysql RELEASE_LOCK must be called from the same conn, so
	// just do everything over a single conn anyway.
	conn     *sql.Conn
	db       *sql.DB
	isLocked atomic.Bool

	config *Config

View on GitHub (pinned to 01a9643f14)

Solutions

  1. Verify the x-tls-ca file is non-empty valid PEM (-----BEGIN CERTIFICATE----- blocks)
  2. Convert DER to PEM: openssl x509 -inform der -in cert.der -out cert.pem
  3. Check file permissions/mounting so the process actually reads the intended cert
  4. Re-download or re-export the CA bundle without losing newlines

Example fix

// before (DSN)
user:pass@tcp(db:3306)/mydb?tls=custom&x-tls-ca=/etc/certs/ca.der
// after
# openssl x509 -inform der -in ca.der -out ca.pem
user:pass@tcp(db:3306)/mydb?tls=custom&x-tls-ca=/etc/certs/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

pemBytes, err := os.ReadFile(caPath)
if err != nil {
    return err
}
if !strings.Contains(string(pemBytes), "-----BEGIN CERTIFICATE-----") {
    return fmt.Errorf("%s is not PEM-encoded; convert with openssl x509 -inform der", caPath)
}

Try / catch

if err != nil {
    if errors.Is(err, mysql.ErrAppendPEM) {
        return fmt.Errorf("x-tls-ca file is not parseable PEM: re-export/convert the cert")
    }
    return err
}

Prevention

When it happens

Trigger: x-tls-ca pointing to a file that is empty, HTML/text instead of PEM, a DER-encoded cert not converted to PEM, concatenated files with garbage between blocks, truncated download of the CA bundle.

Common situations: Secrets mounted as the wrong file, cert exported from Windows in DER/PKCS#7 format, Kubernetes ConfigMap with stripped newlines, copy-pasted cert losing line breaks.

Related errors


AI-assisted analysis of golang-migrate/migrate@01a9643f14 (2026-09-02). Data as JSON: /api/errors/b401f1cb67b59f44. Report an issue: GitHub.