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 *ConfigView on GitHub (pinned to 01a9643f14)
Solutions
- Verify the x-tls-ca file is non-empty valid PEM (-----BEGIN CERTIFICATE----- blocks)
- Convert DER to PEM: openssl x509 -inform der -in cert.der -out cert.pem
- Check file permissions/mounting so the process actually reads the intended cert
- 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
- Verify CA files parse with `openssl x509 -in ca.pem -noout` before deploying
- Convert DER/PKCS#7 exports to PEM
- Ensure secret mounts preserve newlines (no flattened ConfigMap values)
- Check file permissions so the app reads the real cert, not an empty file
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.