{"record":{"id":"53e569cc38f326d2","repo":"amir20/dozzle","slug":"failed-to-parse-certificate-w","errorCode":null,"errorMessage":"failed to parse certificate: %w","messagePattern":"failed to parse certificate: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/agent/client.go","lineNumber":49,"sourceCode":"\ntype Client struct {\n\tclient       pb.AgentServiceClient\n\tconn         *grpc.ClientConn\n\tendpoint     string\n\tnameOverride string\n\tgroup        string\n}\n\nfunc NewClient(endpoint string, certificates tls.Certificate, opts ...grpc.DialOption) (*Client, error) {\n\tendpoint, nameOverride, group, err := ParseEndpoint(endpoint)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tcaCertPool := x509.NewCertPool()\n\tc, err := x509.ParseCertificate(certificates.Certificate[0])\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse certificate: %w\", err)\n\t}\n\tcaCertPool.AddCert(c)\n\ttlsConfig := &tls.Config{\n\t\tCertificates:       []tls.Certificate{certificates},\n\t\tRootCAs:            caCertPool,\n\t\tInsecureSkipVerify: true, // Set to true if the server's hostname does not match the certificate\n\t}\n\n\t// Create the gRPC transport credentials\n\tcreds := credentials.NewTLS(tlsConfig)\n\n\topts = append(opts,\n\t\tgrpc.WithTransportCredentials(creds),\n\t\tgrpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(10*1024*1024), grpc.UseCompressor(gzip.Name)),\n\t\tgrpc.WithKeepaliveParams(keepalive.ClientParameters{\n\t\t\tTime:                30 * time.Second,\n\t\t\tTimeout:             10 * time.Second,\n\t\t\tPermitWithoutStream: true,","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/amir20/dozzle/blob/d9463cbe21874e44ab79db6fa63e746ca7d22928/internal/agent/client.go#L31-L67","documentation":"NewClient fails with \"failed to parse certificate: %w\" when x509.ParseCertificate cannot decode the DER bytes of the leaf certificate loaded from shared_cert.pem. This means the certificate file exists but its contents are corrupt, truncated, or not a valid X.509 certificate.","triggerScenarios":"agent.NewClient(endpoint, certificates) is called and certificates.Certificate[0] (the leaf DER bytes from the shared cert file) cannot be parsed by crypto/x509.","commonSituations":"shared_cert.pem regenerated or corrupted mid-deploy so clients hold a stale/mismatched copy; file mounted empty or with placeholder text; an old client image using certs from a newer algorithm; copying the PEM text file where DER bytes were expected.","solutions":["Regenerate the shared certificates with `make generate` on the host and restart both agent and server so both sides use the same keypair","Verify shared_cert.pem is a valid PEM certificate: `openssl x509 -in shared_cert.pem -text -noout`; replace if it errors","Ensure the cert volume/mount is complete and not truncated (check file size and that the container sees the updated file)","Check for version skew: upgrade client and agent to the same Dozzle release"],"exampleFix":"// before\ncertPEM, _ := os.ReadFile(\"stale-shared_cert.pem\")\ncertificates, err := tls.X509KeyPair(certPEM, keyPEM) // leaf may be corrupt\nclient, err := agent.NewClient(endpoint, certificates)\n// after\ncertPEM, err := os.ReadFile(\"shared_cert.pem\") // regenerated via make generate\nif err != nil { return err }\nif _, err := tls.X509KeyPair(certPEM, keyPEM); err != nil {\n    return fmt.Errorf(\"invalid shared cert, regenerate with make generate: %w\", err)\n}\nclient, err := agent.NewClient(endpoint, certificates)","handlingStrategy":"validation","validationCode":"certPEM, err := os.ReadFile(\"shared_cert.pem\")\nif err != nil { return err }\nif _, err := tls.X509KeyPair(certPEM, keyPEM); err != nil {\n    return fmt.Errorf(\"corrupt shared cert; run make generate: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"client, err := agent.NewClient(endpoint, certs)\nif err != nil {\n    if strings.Contains(err.Error(), \"failed to parse certificate\") {\n        log.Fatal().Err(err).Msg(\"regenerate shared certs with make generate\")\n    }\n    return err\n}","preventionTips":["Regenerate and redistribute shared_cert.pem/shared_key.pem atomically on both server and agent after `make generate`","Verify certs with `openssl x509 -in shared_cert.pem -text -noout` before deploying","Mount the cert files read-only and ensure volume contents are fully synced before starting clients"],"tags":["go","tls","x509","grpc","agent"],"backgroundTag":"tls-certificate-parse-failed","analyzedSha":"d9463cbe21874e44ab79db6fa63e746ca7d22928","analyzedAt":"2026-09-07T10:08:55.855Z","contentChangedAt":"2026-09-07T10:08:55.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}