txthinking/brook · error
failed to parse root certificate
Error message
failed to parse root certificate
What it means
NewBrookLink builds a TLS config for ws/wss-based brook links. When the link contains a 'ca' query parameter, its PEM content is parsed into an x509 CertPool; if AppendCertsFromPEM fails (no valid PEM certificates found), the link is rejected with this error. It signals the embedded CA material is malformed, truncated, or not PEM-encoded.
Source
Thrown at brooklink.go:99
if kind == "wsserver" || kind == "wssserver" || kind == "quicserver" {
if v.Get("address") != "" {
address = v.Get("address")
}
}
if kind == "wssserver" || kind == "quicserver" {
h, _, err := net.SplitHostPort(u.Host)
if err != nil {
return nil, err
}
tc = &tls.Config{ServerName: h}
if v.Get("insecure") == "true" {
tc.InsecureSkipVerify = true
}
if v.Get("ca") != "" {
roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM([]byte(v.Get("ca")))
if !ok {
return nil, errors.New("failed to parse root certificate")
}
tc.RootCAs = roots
}
if kind == "wssserver" {
tc.NextProtos = []string{"http/1.1"}
}
if kind == "quicserver" {
tc.NextProtos = []string{"h3"}
}
}
if kind == "wsserver" || kind == "wssserver" || kind == "quicserver" {
if v.Get("withoutBrookProtocol") == "true" {
p, err = SHA256Bytes([]byte(v.Get("password")))
if err != nil {
return nil, err
}
}
}View on GitHub (pinned to 5cd13ef3b1)
Solutions
- Re-encode the CA certificate as PEM (openssl x509 -inform DER -outform PEM) and percent-encode it fully when embedding in the link URL
- Verify the 'ca' parameter contains at least one complete '-----BEGIN CERTIFICATE-----' block with intact base64 lines
- If the CA is a system CA, drop the 'ca' parameter entirely instead of embedding it
- Test the PEM standalone: Go's AppendCertsFromPEM returns false only when no cert was added
Example fix
// before blk := "wss://example.com/ws?ca=" + url.QueryEscape(strings.ReplaceAll(string(pemBytes), "\n", "")) // after blk := "wss://example.com/ws?ca=" + url.QueryEscape(string(pemBytes))
Defensive patterns
Strategy: validation
Validate before calling
func validCAPEM(ca string) bool {
if ca == "" || !strings.Contains(ca, "-----BEGIN CERTIFICATE-----") {
return false
}
pool := x509.NewCertPool()
return pool.AppendCertsFromPEM([]byte(ca))
}
// before building the link: if !validCAPEM(caParam) { /* fix PEM/encoding */ } Try / catch
if blk, err := NewBrookLink(link); err != nil {
if strings.Contains(err.Error(), "failed to parse root certificate") {
// re-encode CA to PEM and rebuild link
}
return err
} Prevention
- Always PEM-encode CA certs and percent-encode the full string in the URL
- Verify PEM round-trips with AppendCertsFromPEM before embedding
- Prefer dropping 'ca' for public/system CAs
When it happens
Trigger: Creating a brook link (e.g. via NewRelayOverBrook) whose wss/wssserver URL has a 'ca' parameter containing data that x509.CertPool.AppendCertsFromPEM cannot parse as any PEM certificate block.
Common situations: CA cert pasted into the URL without proper PEM encoding or percent-encoding (newlines lost/mangled); truncated certificate; DER-encoded cert supplied instead of PEM; empty or whitespace/garbage value for 'ca'.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
AI-assisted analysis of txthinking/brook@5cd13ef3b1 (2026-09-06).
Data as JSON: /api/errors/9bada43d7ede7dcd.
Report an issue: GitHub.