{"record":{"id":"ad3f3a448b26182c","repo":"gravitational/teleport","slug":"chain-not-allowed-with-an-empty-certificate","errorCode":null,"errorMessage":"chain not allowed with an empty certificate","messagePattern":"chain not allowed with an empty certificate","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/subca/parsed.go","lineNumber":268,"sourceCode":"\t\t}\n\t}\n\n\t// Validate \"required\" fields now that we know both Certificate and PublicKey\n\t// are valid.\n\tswitch {\n\tcase co.GetDisabled() && co.GetPublicKey() == \"\" && co.GetCertificate() == \"\":\n\t\treturn nil, \"\", errors.New(\"certificate or public key required\")\n\tcase co.GetDisabled():\n\t\t// OK, determined above to have either PublicKey or Certificate.\n\tcase co.GetCertificate() == \"\":\n\t\treturn nil, \"\", errors.New(\"certificate required\")\n\t}\n\n\t// Chain.\n\tvar chain []*x509.Certificate\n\tif len(co.GetChain()) > 0 {\n\t\tif cert == nil {\n\t\t\treturn nil, \"\", errors.New(\"chain not allowed with an empty certificate\")\n\t\t}\n\n\t\t// The exact number is arbitrary, the fact that a cap exists isn't.\n\t\tconst maxChainLength = 10\n\t\tif len(co.GetChain()) > maxChainLength {\n\t\t\treturn nil, \"chain\", fmt.Errorf(\n\t\t\t\t\"certificate chain has too many entries (%d > %d)\", len(co.GetChain()), maxChainLength)\n\t\t}\n\n\t\tchain = make([]*x509.Certificate, len(co.GetChain()))\n\t\tprev := cert\n\t\tfor i, chainPEM := range co.GetChain() {\n\t\t\tchainCert, err := ParseCertificateOverrideCertificate(chainPEM)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Sprintf(\"chain[%d]\", i), err\n\t\t\t}\n\t\t\tchainSub := chainCert.Subject.String()\n","sourceCodeStart":250,"sourceCodeEnd":286,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/subca/parsed.go#L250-L286","documentation":"In lib/subca/parsed.go, validateCertificateOverride parses the optional certificate and chain fields of a CA override. If a chain is supplied but no override certificate is set, there is no leaf/issuer anchor to attach the chain to, so the function rejects the combination with this error. The library requires the override certificate itself to be provided whenever an intermediate chain accompanies it.","triggerScenarios":"Calling ValidateAndParseCAOverride with a CAOverride spec whose 'chain' field is non-empty while 'cert' is empty or nil. Typically a YAML/manifest that defines chain entries (intermediates) but omits the main override certificate.","commonSituations":"Operators pasting a full PEM bundle into 'chain' but forgetting the leaf CA in 'cert'; templates that split a PEM into the wrong fields; automation that strips the first certificate into a separate variable and ends up with an empty cert.","solutions":["Set the override certificate (co.Cert) to the issuing CA certificate that the chain extends.","If the first certificate in your PEM is actually the override certificate, move it from 'chain' into the certificate field.","If no chain is needed, remove the chain entries entirely instead of leaving them with an empty cert."],"exampleFix":"// before\nspec:\n  cert: \"\"\n  chain:\n    - |\n      -----BEGIN CERTIFICATE-----\n      ...(intermediate)...\n// after\nspec:\n  cert: |\n    -----BEGIN CERTIFICATE-----\n    ...(override CA)...\n  chain:\n    - |\n      -----BEGIN CERTIFICATE-----\n      ...(intermediate)...","handlingStrategy":"validation","validationCode":"if len(override.Chain) > 0 && override.Cert == \"\" {\n    return fmt.Errorf(\"invalid config: chain requires a certificate\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate CA override manifests (cert present iff needed, chain under 10 entries) before applying them.","Script PEM splitting so the first certificate goes to 'cert', the rest to 'chain'.","Never leave 'chain' populated with an empty 'cert' field in templates."],"tags":["x509","certificate","configuration","validation"],"backgroundTag":"ca-override-chain-validation","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}