{"record":{"id":"bb698885badd9b6d","repo":"gravitational/teleport","slug":"certificate-required","errorCode":null,"errorMessage":"certificate required","messagePattern":"certificate required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/subca/parsed.go","lineNumber":261,"sourceCode":"\t// PublicKey.\n\tif co.GetPublicKey() != \"\" {\n\t\tif !certificateOverridePublicKeyRE.MatchString(co.GetPublicKey()) {\n\t\t\treturn nil, \"\", errors.New(\"invalid public key\")\n\t\t}\n\t\tif wantPublicKey != \"\" && NormalizePublicKey(co.GetPublicKey()) != wantPublicKey {\n\t\t\treturn nil, \"public_key\", fmt.Errorf(\"certificate public key mismatch (want %q)\", wantPublicKey)\n\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","sourceCodeStart":243,"sourceCodeEnd":279,"githubUrl":"https://github.com/gravitational/teleport/blob/1283425b60ec5f60d509ba4c791183d452923ff7/lib/subca/parsed.go#L243-L279","documentation":"An enabled (not disabled) certificate override must supply a certificate — a public key alone is insufficient for an active override because the CA needs the actual certificate to issue from. validateCertificateOverride returns this error when co.Disabled is false and co.Certificate is empty.","triggerScenarios":"Creating a SubCA certificate override with only public_key set and disabled false (or unset), reaching the final case of the required-fields switch.","commonSituations":"Intending to disable an override but forgetting disabled:true while omitting the certificate; using a public-key-only spec copied from a disabled override.","solutions":["Provide the PEM certificate in the override's certificate field","Set disabled: true if the override is only meant to pin/deny a key without active issuance"],"exampleFix":"// before (enabled override, no cert)\noverride:\n  public_key: <pem>\n// after\noverride:\n  certificate: |\n    -----BEGIN CERTIFICATE-----\n    ...\n    -----END CERTIFICATE-----","handlingStrategy":"validation","validationCode":"if !override.GetDisabled() && override.GetCertificate() == \"\" {\n    return trace.BadParameter(\"enabled certificate override requires a certificate\")\n}","typeGuard":"func isEnabledOverrideComplete(o *subcav1.CertificateOverride) bool {\n    return o != nil && (o.GetDisabled() || o.GetCertificate() != \"\")\n}","tryCatchPattern":"if _, _, err := ValidateAndParseCAOverride(clusterName, co); err != nil {\n    if strings.Contains(err.Error(), \"certificate required\") {\n        return trace.BadParameter(\"provide a PEM certificate or set disabled: true\")\n    }\n    return trace.Wrap(err)\n}","preventionTips":["Set disabled:true for key-only overrides","Always include the PEM certificate for active overrides","Validate specs in CI before applying SubCA resources"],"tags":["subca","validation","x509","config"],"backgroundTag":"certificate-required","analyzedSha":"1283425b60ec5f60d509ba4c791183d452923ff7","analyzedAt":"2026-09-02T04:06:41.601Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}