{"record":{"id":"7ff65b7347be2a39","repo":"docker/cli","slug":"rotating-to-an-external-ca-requires-the-s-fla","errorCode":null,"errorMessage":"rotating to an external CA requires the `--%s` flag to specify the external CA's cert - to add an external CA with the current root CA certificate, use the `update` command instead","messagePattern":"rotating to an external CA requires the `--(.+?)` flag to specify the external CA's cert - to add an external CA with the current root CA certificate, use the `update` command instead","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/swarm/ca.go","lineNumber":76,"sourceCode":"func runCA(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, opts caOptions) error {\n\tapiClient := dockerCLI.Client()\n\n\tres, err := apiClient.SwarmInspect(ctx, client.SwarmInspectOptions{})\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tif !opts.rotate {\n\t\tfor _, f := range []string{flagCACert, flagCAKey, flagCertExpiry, flagExternalCA} {\n\t\t\tif flags.Changed(f) {\n\t\t\t\treturn fmt.Errorf(\"`--%s` flag requires the `--rotate` flag to update the CA\", f)\n\t\t\t}\n\t\t}\n\t\treturn displayTrustRoot(dockerCLI.Out(), res)\n\t}\n\n\tif flags.Changed(flagExternalCA) && len(opts.externalCA.Value()) > 0 && !flags.Changed(flagCACert) {\n\t\treturn fmt.Errorf(\n\t\t\t\"rotating to an external CA requires the `--%s` flag to specify the external CA's cert - \"+\n\t\t\t\t\"to add an external CA with the current root CA certificate, use the `update` command instead\", flagCACert)\n\t}\n\n\tif flags.Changed(flagCACert) && len(opts.externalCA.Value()) == 0 && !flags.Changed(flagCAKey) {\n\t\treturn fmt.Errorf(\"the --%s flag requires that a --%s flag and/or --%s flag be provided as well\",\n\t\t\tflagCACert, flagCAKey, flagExternalCA)\n\t}\n\n\tupdateSwarmSpec(&res.Swarm.Spec, flags, opts)\n\tif _, err := apiClient.SwarmUpdate(ctx, client.SwarmUpdateOptions{\n\t\tVersion: res.Swarm.Version,\n\t\tSpec:    res.Swarm.Spec,\n\t}); err != nil {\n\t\treturn err\n\t}\n\n\tif opts.detach {","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/swarm/ca.go#L58-L94","documentation":"Thrown by 'docker swarm ca --rotate' when --external-ca specifies a non-empty CA but --ca-cert is not provided. Rotating TO an external CA requires supplying the external CA's certificate; to attach an external CA keeping the current root, the 'update' command is the supported path.","triggerScenarios":"Running 'docker swarm ca --rotate --external-ca protocol=cfssl,url=https://ca.example.com' (a populated external-ca spec) without --ca-cert. The guard at ca.go:75 checks flags.Changed(flagExternalCA), len(opts.externalCA.Value()) > 0, and !flags.Changed(flagCACert).","commonSituations":"Operator confuses adding an external CA (docker swarm update) with rotating the root to an external CA (docker swarm ca --rotate); copy-pasting an external-ca spec without the matching cert; missing the cert file path.","solutions":["Provide the external CA's cert: 'docker swarm ca --rotate --external-ca protocol=cfssl,url=https://ca --ca-cert ./ext-ca.pem'.","If you want to ADD an external CA while keeping the current root, use 'docker swarm update --external-ca ...' instead.","Confirm the external CA URL and cert correspond to the same CA before rotating."],"exampleFix":"# before\ndocker swarm ca --rotate --external-ca protocol=cfssl,url=https://ca.example.com\n\n# after\ndocker swarm ca --rotate --external-ca protocol=cfssl,url=https://ca.example.com --ca-cert ./ext-ca.pem\n# -or- add without rotating root:\ndocker swarm update --external-ca protocol=cfssl,url=https://ca.example.com","handlingStrategy":"validation","validationCode":"// Validate: rotating to external CA requires --ca-cert\nif flags.Changed(flagRotate) && flags.Changed(flagExternalCA) && len(externalCA.Value()) > 0 && !flags.Changed(flagCACert) {\n    return errors.New(\"--ca-cert required when rotating to external CA; use 'swarm update' to add one without rotating\")\n}","typeGuard":"func isExternalCARotationToExternal(flags *pflag.FlagSet, ext Value) bool {\n\treturn flags.Changed(flagRotate) && flags.Changed(flagExternalCA) && len(ext.Value()) > 0\n}","tryCatchPattern":null,"preventionTips":["Distinguish 'rotate root to external CA' (ca --rotate) from 'add external CA' (update).","Always supply --ca-cert matching the external CA when rotating.","Document which operation your runbook intends."],"tags":["swarm","ca","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"}