{"record":{"id":"38191d23749f437f","repo":"docker/cli","slug":"unrecognized-external-ca-protocol-s","errorCode":null,"errorMessage":"unrecognized external CA protocol %s","messagePattern":"unrecognized external CA protocol (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/swarm/opts.go","lineNumber":190,"sourceCode":"\tvar (\n\t\thasProtocol bool\n\t\thasURL      bool\n\t)\n\n\tfor _, field := range fields {\n\t\tkey, value, ok := strings.Cut(field, \"=\")\n\t\tif !ok {\n\t\t\treturn nil, fmt.Errorf(\"invalid field '%s' must be a key=value pair\", field)\n\t\t}\n\n\t\t// TODO(thaJeztah): these options should not be case-insensitive.\n\t\tswitch strings.ToLower(key) {\n\t\tcase \"protocol\":\n\t\t\thasProtocol = true\n\t\t\tif strings.ToLower(value) == string(swarm.ExternalCAProtocolCFSSL) {\n\t\t\t\texternalCA.Protocol = swarm.ExternalCAProtocolCFSSL\n\t\t\t} else {\n\t\t\t\treturn nil, fmt.Errorf(\"unrecognized external CA protocol %s\", value)\n\t\t\t}\n\t\tcase \"url\":\n\t\t\thasURL = true\n\t\t\texternalCA.URL = value\n\t\tcase \"cacert\":\n\t\t\tcacontents, err := os.ReadFile(value)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"unable to read CA cert for external CA: %w\", err)\n\t\t\t}\n\t\t\tif pemBlock, _ := pem.Decode(cacontents); pemBlock == nil {\n\t\t\t\treturn nil, errors.New(\"CA cert for external CA must be in PEM format\")\n\t\t\t}\n\t\t\texternalCA.CACert = string(cacontents)\n\t\tdefault:\n\t\t\texternalCA.Options[key] = value\n\t\t}\n\t}\n","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/swarm/opts.go#L172-L208","documentation":"Raised by parseExternalCA when the protocol= field is not 'cfssl' (case-insensitive). The only supported ExternalCAProtocol value is swarm.ExternalCAProtocolCFSSL; any other value is rejected.","triggerScenarios":"Passing '--external-ca protocol=vault,url=...' or protocol=https, etc. Only 'cfssl' is accepted at opts.go:187-191.","commonSituations":"Operator assumes HashiCorp Vault or a generic HTTPS CA is supported directly; case mismatch is not the issue (it's lowercased), only the value matters.","solutions":["Use protocol=cfssl, which is the only supported external CA protocol in this version.","Point the cfssl URL at your own signing service that speaks the cfssl API.","If you need a different CA integration, use a sidecar that exposes the cfssl protocol."],"exampleFix":"# before\ndocker swarm init --external-ca protocol=vault,url=https://vault:8200\n\n# after\ndocker swarm init --external-ca protocol=cfssl,url=https://my-cfssl-signer:8888","handlingStrategy":"validation","validationCode":"// Validate protocol before parse\nif !strings.EqualFold(proto, string(swarm.ExternalCAProtocolCFSSL)) {\n    return fmt.Errorf(\"unsupported external CA protocol %q; only cfssl\", proto)\n}","typeGuard":"func isSupportedCAProtocol(s string) bool {\n\treturn strings.EqualFold(s, string(swarm.ExternalCAProtocolCFSSL))\n}","tryCatchPattern":null,"preventionTips":["Use protocol=cfssl only.","Front any non-cfssl CA with a cfssl-protocol adapter.","Track supported protocols per CLI version."],"tags":["swarm","external-ca","validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}