{"record":{"id":"19f0ac9810a1fa7a","repo":"docker/cli","slug":"cannot-mix-cluster-options-with-mount-type-s","errorCode":null,"errorMessage":"cannot mix 'cluster-*' options with mount type '%s'","messagePattern":"cannot mix 'cluster-\\*' options with mount type '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"opts/mount_utils.go","lineNumber":65,"sourceCode":"func validateExclusiveOptions(m *mount.Mount) error {\n\tif m.Type == \"\" {\n\t\treturn errors.New(\"type is required\")\n\t}\n\n\tif m.Type != mount.TypeBind && m.BindOptions != nil {\n\t\treturn fmt.Errorf(\"cannot mix 'bind-*' options with mount type '%s'\", m.Type)\n\t}\n\tif m.Type != mount.TypeVolume && m.VolumeOptions != nil {\n\t\treturn fmt.Errorf(\"cannot mix 'volume-*' options with mount type '%s'\", m.Type)\n\t}\n\tif m.Type != mount.TypeImage && m.ImageOptions != nil {\n\t\treturn fmt.Errorf(\"cannot mix 'image-*' options with mount type '%s'\", m.Type)\n\t}\n\tif m.Type != mount.TypeTmpfs && m.TmpfsOptions != nil {\n\t\treturn fmt.Errorf(\"cannot mix 'tmpfs-*' options with mount type '%s'\", m.Type)\n\t}\n\tif m.Type != mount.TypeCluster && m.ClusterOptions != nil {\n\t\treturn fmt.Errorf(\"cannot mix 'cluster-*' options with mount type '%s'\", m.Type)\n\t}\n\treturn nil\n}\n\n// parseBoolValue returns the boolean value represented by the string. It returns\n// true if no value is set.\n//\n// It is similar to [strconv.ParseBool], but only accepts 1, true, 0, false.\n// Any other value returns an error.\nfunc parseBoolValue(key string, val string, hasValue bool) (bool, error) {\n\tif !hasValue {\n\t\treturn true, nil\n\t}\n\tswitch val {\n\tcase \"1\", \"true\":\n\t\treturn true, nil\n\tcase \"0\", \"false\":\n\t\treturn false, nil","sourceCodeStart":47,"sourceCodeEnd":83,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/opts/mount_utils.go#L47-L83","documentation":"Returned by validateExclusiveOptions (opts/mount_utils.go:65) when a mount's Type is not TypeCluster but ClusterOptions is non-nil. The cluster-* options are exclusive to type=cluster mounts.","triggerScenarios":"Setting cluster options on a bind/volume/tmpfs/image mount, or programmatically setting mount.ClusterOptions on a Mount whose Type isn't TypeCluster. This is the swarm/cluster-mount variant of the other exclusive-option checks.","commonSituations":"Using cluster-mount options in a standalone container context, or a generator emitting ClusterOptions unconditionally.","solutions":["Use type=cluster when you need cluster-* options.","Or remove cluster options from non-cluster mounts."],"exampleFix":"// before\nmount := mount.Mount{Type: mount.TypeVolume, ClusterOptions: &mount.ClusterOptions{}}\n\n// after\nmount := mount.Mount{Type: mount.TypeCluster, ClusterOptions: &mount.ClusterOptions{}}","handlingStrategy":"validation","validationCode":"func validateExclusive(m mount.Mount) error {\n    if m.Type != mount.TypeCluster && m.ClusterOptions != nil {\n        return fmt.Errorf(\"cluster-* options require type=cluster, got %s\", m.Type)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := m.Set(spec); err != nil {\n    return fmt.Errorf(\"mount %q: %w\", spec, err)\n}","preventionTips":["Only attach ClusterOptions when Type == TypeCluster.","Keep cluster-mount construction separate from standalone mounts.","Test swarm mount specs for correct type/options pairing."],"tags":["mount","docker","cluster","exclusive-options","validation"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}