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

  1. Convert DER to PEM: openssl x509 -inform der -in cert.cer -out ca.pem.
  2. Verify the file contains PEM blocks: openssl x509 -in ca.pem -noout -subject.
  3. 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

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

Related errors


AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04). Data as JSON: /api/errors/2c27d5d46efb0bca. Report an issue: GitHub.