larksuite/cli · error
invalid %s %q: no certificates parsed from PEM
Error message
invalid %s %q: no certificates parsed from PEM
What it means
The extra root CA file was read but AppendCertsFromPEM parsed zero certificates from its contents. This means the file is not valid PEM (wrong format, DER-encoded binary, empty, or garbage), so the CLI refuses to add it to the trust pool.
Source
Thrown at internal/transport/tls_ca.go:54
}
pemBytes, err := vfs.ReadFile(safeCAPath)
if err != nil {
return fmt.Errorf("failed to read %s %q: %w", envvars.CliCAPath, caPath, err)
}
// Augment the system trust store. Do NOT silently discard a SystemCertPool
// error: falling back to an empty pool would make this transport trust ONLY
// the extra CA (dropping all system roots), which narrows trust unexpectedly
// and could break TLS to legitimate endpoints. Fail closed instead.
pool, err := x509.SystemCertPool()
if err != nil {
return fmt.Errorf("failed to load system cert pool for %s: %w", envvars.CliCAPath, err)
}
if pool == nil {
pool = x509.NewCertPool()
}
if ok := pool.AppendCertsFromPEM(pemBytes); !ok {
return fmt.Errorf("invalid %s %q: no certificates parsed from PEM", envvars.CliCAPath, caPath)
}
if t.TLSClientConfig == nil {
t.TLSClientConfig = &tls.Config{}
} else {
// Clone to avoid mutating shared config from the base transport.
t.TLSClientConfig = t.TLSClientConfig.Clone()
}
if t.TLSClientConfig.MinVersion == 0 || t.TLSClientConfig.MinVersion < tls.VersionTLS12 {
t.TLSClientConfig.MinVersion = tls.VersionTLS12
}
t.TLSClientConfig.RootCAs = pool
return nil
}
View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Convert DER to PEM: openssl x509 -inform der -in cert.cer -out ca.pem.
- Verify the file contains PEM blocks: openssl x509 -in ca.pem -noout -subject.
- Re-export the certificate in PEM format from the issuing source and re-point CLI_CA_PATH at it.
Example fix
// before openssl s_client -showcerts ... > ca.pem # may capture non-PEM noise // after openssl x509 -inform der -in cert.cer -out /etc/lark-cli/ca.pem
Defensive patterns
Strategy: validation
Validate before calling
pemBytes, err := os.ReadFile(caPath)
if err != nil { return err }
if !x509.NewCertPool().AppendCertsFromPEM(pemBytes) {
return fmt.Errorf("%s contains no PEM certificates", caPath)
} Type guard
func isPEMCertificate(path string) bool {
b, err := os.ReadFile(path)
if err != nil { return false }
block, _ := pem.Decode(b)
return block != nil && block.Type == "CERTIFICATE"
} Prevention
- Convert DER certs to PEM with 'openssl x509 -inform der' before use.
- Validate with 'openssl x509 -in ca.pem -noout -subject' during provisioning.
- Store only certificate bundles, never pages or keys, at CLI_CA_PATH.
When it happens
Trigger: CLI_CA_PATH points to a file that exists and is readable, but its bytes contain no '-----BEGIN CERTIFICATE-----' PEM blocks; raised in applyExtraRootCA after pool.AppendCertsFromPEM returns false.
Common situations: Downloading a DER (.cer/.crt binary) cert instead of PEM; saving an HTML error page as ca.pem; concatenating only private keys or an expired/empty bundle.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- invalid %s %q: must be an absolute path to a PEM file
- unsafe %s %q: %w
- failed to read %s %q: %w
- failed to load system cert pool for %s: %w
- Invalid column: {col}
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/2c27d5d46efb0bca.
Report an issue: GitHub.