{"record":{"id":"135d7f1a69525fbe","repo":"caddyserver/caddy","slug":"no-client-certificate-provided","errorCode":null,"errorMessage":"no client certificate provided","messagePattern":"no client certificate provided","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/connpolicy.go","lineNumber":1033,"sourceCode":"\t\tmod, err := caddyfile.UnmarshalModule(d, \"tls.leaf_cert_loader.\"+modName)\n\t\tif err != nil {\n\t\t\treturn d.WrapErr(err)\n\t\t}\n\t\tvMod, ok := mod.(LeafCertificateLoader)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"leaf module '%s' is not a leaf certificate loader\", vMod)\n\t\t}\n\t\tl.LeafCertificateLoadersRaw = append(\n\t\t\tl.LeafCertificateLoadersRaw,\n\t\t\tcaddyconfig.JSONModuleObject(vMod, \"loader\", modName, nil),\n\t\t)\n\t}\n\treturn nil\n}\n\nfunc (l LeafCertClientAuth) VerifyClientCertificate(rawCerts [][]byte, _ [][]*x509.Certificate) error {\n\tif len(rawCerts) == 0 {\n\t\treturn fmt.Errorf(\"no client certificate provided\")\n\t}\n\n\tremoteLeafCert, err := x509.ParseCertificate(rawCerts[0])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"can't parse the given certificate: %s\", err.Error())\n\t}\n\n\tif slices.ContainsFunc(l.trustedLeafCerts, remoteLeafCert.Equal) {\n\t\treturn nil\n\t}\n\n\treturn fmt.Errorf(\"client leaf certificate failed validation\")\n}\n\n// PublicKeyAlgorithm is a JSON-unmarshalable wrapper type.\ntype PublicKeyAlgorithm x509.PublicKeyAlgorithm\n\n// UnmarshalJSON satisfies json.Unmarshaler.","sourceCodeStart":1015,"sourceCodeEnd":1051,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/connpolicy.go#L1015-L1051","documentation":"LeafCertClientAuth.VerifyClientCertificate is the callback Go TLS invokes with the peer's raw certificate chain; if the slice is empty (no certificate was presented) it fails with this error. In practice it fires when the TLS mode let the handshake reach verification without a client cert — e.g. mode request combined with a leaf verifier, or a client that sent an empty Certificate message.","triggerScenarios":"client_auth mode 'request' (or verify_if_given) with a leaf verifier: the client sends no certificate and Go still calls the custom verifier path in some configurations; a client connecting without any cert configured when verification is active.","commonSituations":"Testing mTLS endpoints with plain curl (no --cert) while a leaf verifier is configured; clients with a cert that fails to load and silently send none; policy mismatch between mode and verifiers.","solutions":["Send a client certificate: curl --cert client.pem --key client.key https://host/","Align the mode with your intent: use require_and_verify so missing certs are rejected earlier and clearly","Confirm the client actually loads its cert (check client-side logs; many tools warn when a cert file fails to parse)","If some clients legitimately have no cert, use verify_if_given and ensure your verifier tolerates that path per current Caddy semantics"],"exampleFix":"# before\ncurl https://mtls.example.com/\n\n# after\ncurl --cert client.pem --key client.key https://mtls.example.com/","handlingStrategy":"validation","validationCode":"// Client-side: verify you actually have a cert+key pair before connecting\nfunc canPresentCert(certFile, keyFile string) error {\n\tcert, err := tls.LoadX509KeyPair(certFile, keyFile)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"client cert unusable: %w\", err)\n\t}\n\t_ = cert\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"// Server-side logging: distinguish missing vs untrusted client certs\nif err := conn.VerifyConnection(...); err != nil { /* caddy logs it */ }\n// In access logs / metrics, alert on TLS handshake failures per client IP to catch cert-less clients","preventionTips":["Use mode require_and_verify for strict mTLS so empty-certificate clients are rejected with standard alerts","Automate client cert provisioning so clients never connect without one","Monitor handshake failure rates as an operational signal"],"tags":["tls","mtls","client-cert","handshake"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}