docker/cli · error
rotating to an external CA requires the
Error message
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
What it means
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.
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.
Example fix
# before docker swarm ca --rotate --external-ca protocol=cfssl,url=https://ca.example.com # after docker swarm ca --rotate --external-ca protocol=cfssl,url=https://ca.example.com --ca-cert ./ext-ca.pem # -or- add without rotating root: docker swarm update --external-ca protocol=cfssl,url=https://ca.example.com
Defensive patterns
Strategy: validation
Validate before calling
// Validate: rotating to external CA requires --ca-cert
if flags.Changed(flagRotate) && flags.Changed(flagExternalCA) && len(externalCA.Value()) > 0 && !flags.Changed(flagCACert) {
return errors.New("--ca-cert required when rotating to external CA; use 'swarm update' to add one without rotating")
} Type guard
func isExternalCARotationToExternal(flags *pflag.FlagSet, ext Value) bool {
return flags.Changed(flagRotate) && flags.Changed(flagExternalCA) && len(ext.Value()) > 0
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- file contents must be in PEM format
- CA cert for external CA must be in PEM format
- the external-ca option needs a protocol= parameter
- the external-ca option needs a url= parameter
- `-- ` flag requires the `--rotate` flag to update the CA
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/7ff65b7347be2a39.
Report an issue: GitHub.
Appendix: source
Thrown at cli/command/swarm/ca.go:76
func runCA(ctx context.Context, dockerCLI command.Cli, flags *pflag.FlagSet, opts caOptions) error {
apiClient := dockerCLI.Client()
res, err := apiClient.SwarmInspect(ctx, client.SwarmInspectOptions{})
if err != nil {
return err
}
if !opts.rotate {
for _, f := range []string{flagCACert, flagCAKey, flagCertExpiry, flagExternalCA} {
if flags.Changed(f) {
return fmt.Errorf("`--%s` flag requires the `--rotate` flag to update the CA", f)
}
}
return displayTrustRoot(dockerCLI.Out(), res)
}
if flags.Changed(flagExternalCA) && len(opts.externalCA.Value()) > 0 && !flags.Changed(flagCACert) {
return fmt.Errorf(
"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", flagCACert)
}
if flags.Changed(flagCACert) && len(opts.externalCA.Value()) == 0 && !flags.Changed(flagCAKey) {
return fmt.Errorf("the --%s flag requires that a --%s flag and/or --%s flag be provided as well",
flagCACert, flagCAKey, flagExternalCA)
}
updateSwarmSpec(&res.Swarm.Spec, flags, opts)
if _, err := apiClient.SwarmUpdate(ctx, client.SwarmUpdateOptions{
Version: res.Swarm.Version,
Spec: res.Swarm.Spec,
}); err != nil {
return err
}
if opts.detach {View on GitHub (pinned to 4f84911bfe)