{"id":"5330930cf15e12c2","repo":"docker/cli","slug":"ca-cert-for-external-ca-must-be-in-pem-format","errorCode":null,"errorMessage":"CA cert for external CA must be in PEM format","messagePattern":"CA cert for external CA must be in PEM format","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/swarm/opts.go","lineNumber":201,"sourceCode":"\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\n\tif !hasProtocol {\n\t\treturn nil, errors.New(\"the external-ca option needs a protocol= parameter\")\n\t}\n\tif !hasURL {\n\t\treturn nil, errors.New(\"the external-ca option needs a url= parameter\")\n\t}\n\n\treturn &externalCA, nil\n}\n\nfunc addSwarmCAFlags(flags *pflag.FlagSet, options *swarmCAOptions) {","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/docker/cli/blob/e9452d6e785f6e365712b9d71bd7517591773c86/cli/command/swarm/opts.go#L183-L219","documentation":"Raised while parsing an `--external-ca` specification when the file given via the `cacert=` field reads successfully but contains no decodable PEM block. parseExternalCA validates the external CA's certificate client-side with pem.Decode before including it in the swarm spec.","triggerScenarios":"`docker swarm init` or `docker swarm update` with `--external-ca protocol=cfssl,url=...,cacert=<file>` where the referenced file is DER-encoded, empty, truncated, or otherwise missing a `-----BEGIN ...-----` PEM block.","commonSituations":"Downloading a CA certificate from an internal PKI in DER format; passing a bundle in PKCS#7/PKCS#12 format; a deployment templating step writing an empty cacert file; wrong filename in automation.","solutions":["Verify the cacert file begins with `-----BEGIN CERTIFICATE-----`.","Convert to PEM if needed: `openssl x509 -inform der -in ca.crt -out ca.pem`.","Ensure the path in `cacert=` points to the intended, non-empty file.","Re-run the swarm init/update with the corrected file."],"exampleFix":"# before\ndocker swarm update --external-ca protocol=cfssl,url=https://ca.example.com,cacert=ca.der\n# after\nopenssl x509 -inform der -in ca.der -out ca.pem\ndocker swarm update --external-ca protocol=cfssl,url=https://ca.example.com,cacert=ca.pem","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":["docker","swarm","external-ca","pem","certificate"],"analyzedSha":"e9452d6e785f6e365712b9d71bd7517591773c86","analyzedAt":"2026-08-01T07:09:22.474Z","schemaVersion":2}