{"record":{"id":"f74fc5e1a6ed0b82","repo":"docker/cli","slug":"the-external-ca-option-needs-a-url-parameter","errorCode":null,"errorMessage":"the external-ca option needs a url= parameter","messagePattern":"the external-ca option needs a url= parameter","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cli/command/swarm/opts.go","lineNumber":213,"sourceCode":"\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) {\n\tflags.DurationVar(&options.nodeCertExpiry, flagCertExpiry, 90*24*time.Hour, \"Validity period for node certificates (ns|us|ms|s|m|h)\")\n\tflags.Var(&options.externalCA, flagExternalCA, \"Specifications of one or more certificate signing endpoints\")\n}\n\nfunc addSwarmFlags(flags *pflag.FlagSet, options *swarmOptions) {\n\tflags.Int64Var(&options.taskHistoryLimit, flagTaskHistoryLimit, 5, \"Task history retention limit\")\n\tflags.DurationVar(&options.dispatcherHeartbeat, flagDispatcherHeartbeat, 5*time.Second, \"Dispatcher heartbeat period (ns|us|ms|s|m|h)\")\n\tflags.Uint64Var(&options.maxSnapshots, flagMaxSnapshots, 0, \"Number of additional Raft snapshots to retain\")\n\tflags.SetAnnotation(flagMaxSnapshots, \"version\", []string{\"1.25\"})\n\tflags.Uint64Var(&options.snapshotInterval, flagSnapshotInterval, 10000, \"Number of log entries between Raft snapshots\")\n\tflags.SetAnnotation(flagSnapshotInterval, \"version\", []string{\"1.25\"})\n\taddSwarmCAFlags(flags, &options.swarmCAOptions)","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/cli/command/swarm/opts.go#L195-L231","documentation":"Thrown by parseExternalCA (cli/command/swarm/opts.go:213) when an `--external-ca` specification contains no `url=` key. The external CA endpoint URL is mandatory; if hasURL is false after the field loop, parsing aborts.","triggerScenarios":"Passing `--external-ca protocol=cfssl` (url omitted) or any spec missing the `url=` key.","commonSituations":"Forgot the url key; templating dropped it; copy-paste left only the protocol.","solutions":["Add `url=<endpoint>` to the spec: `--external-ca protocol=cfssl,url=https://ca.example.com`.","Validate the spec string contains `url=` before invoking the command."],"exampleFix":"// before\ndocker swarm update --external-ca protocol=cfssl\n\n// after\ndocker swarm update --external-ca protocol=cfssl,url=https://ca.example.com","handlingStrategy":"validation","validationCode":"// Require url= in the external-ca spec string.\nif !strings.Contains(spec, \"url=\") {\n\treturn errors.New(\"external-ca spec needs url=\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use a typed builder for external-ca specs enforcing both keys.","Lint spec strings for both protocol= and url= before invocation.","Keep CA endpoint URLs in config, not hand-typed on the CLI."],"tags":["docker","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"}