{"record":{"id":"ecead33664ed9135","repo":"docker/cli","slug":"option-bind-recursive-writable-requires-readonl","errorCode":null,"errorMessage":"option 'bind-recursive=writable' requires 'readonly' to be specified in conjunction","messagePattern":"option 'bind-recursive=writable' requires 'readonly' to be specified in conjunction","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"opts/mount_utils.go","lineNumber":21,"sourceCode":"import (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/moby/moby/api/types/mount\"\n)\n\n// validateMountOptions performs client-side validation of mount options. Similar\n// validation happens on the daemon side, but this validation allows us to\n// produce user-friendly errors matching command-line options.\nfunc validateMountOptions(m *mount.Mount) error {\n\tif err := validateExclusiveOptions(m); err != nil {\n\t\treturn err\n\t}\n\n\tif m.BindOptions != nil {\n\t\tif m.BindOptions.ReadOnlyNonRecursive && !m.ReadOnly {\n\t\t\treturn errors.New(\"option 'bind-recursive=writable' requires 'readonly' to be specified in conjunction\")\n\t\t}\n\t\tif m.BindOptions.ReadOnlyForceRecursive {\n\t\t\tif !m.ReadOnly {\n\t\t\t\treturn errors.New(\"option 'bind-recursive=readonly' requires 'readonly' to be specified in conjunction\")\n\t\t\t}\n\t\t\tif m.BindOptions.Propagation != mount.PropagationRPrivate {\n\t\t\t\t// FIXME(thaJeztah): this is missing daemon-side validation\n\t\t\t\t//\n\t\t\t\t//\tdocker run --rm --mount type=bind,src=/var/run,target=/foo,bind-recursive=readonly,readonly alpine\n\t\t\t\t//\t# no error\n\t\t\t\treturn errors.New(\"option 'bind-recursive=readonly' requires 'bind-propagation=rprivate' to be specified in conjunction\")\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/docker/cli/blob/4f84911bfe8811e9b028e4b1fee8e7510be79387/opts/mount_utils.go#L3-L39","documentation":"Returned by validateMountOptions (opts/mount_utils.go:21) when BindOptions.ReadOnlyNonRecursive is true (set by 'bind-recursive=writable') but the mount is not also marked read-only (m.ReadOnly is false). The 'writable' recursive mode is specifically designed for the read-only bind-mount behavior of Docker v24, so it only makes sense in conjunction with readonly.","triggerScenarios":"A --mount value includes 'bind-recursive=writable' but does not also include 'readonly' or 'ro'. For example: '--mount type=bind,src=/x,dst=/y,bind-recursive=writable'. validateMountOptions detects ReadOnlyNonRecursive=true with m.ReadOnly=false.","commonSituations":"Misunderstanding that 'bind-recursive=writable' describes the behavior of read-only mounts that are recursively mounted but not recursively read-only — using it without readonly is contradictory.","solutions":["Add 'readonly' (or 'ro') to the --mount spec whenever using 'bind-recursive=writable'.","If you don't need read-only behavior, remove 'bind-recursive=writable' entirely (the default is recursive writable for non-readonly mounts)."],"exampleFix":"// before: missing readonly\n// docker run --mount type=bind,src=/x,dst=/y,bind-recursive=writable nginx\n\n// after: add readonly\n// docker run --mount type=bind,src=/x,dst=/y,readonly,bind-recursive=writable nginx","handlingStrategy":"validation","validationCode":"func validateRecursiveWritable(spec string) error {\n    if strings.Contains(spec, \"bind-recursive=writable\") &&\n        !strings.Contains(spec, \"readonly\") && !strings.Contains(spec, \",ro\") &&\n        !strings.Contains(spec, \"ro=\") {\n        return fmt.Errorf(\"bind-recursive=writable requires readonly to also be specified\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if err := mountOpt.Set(value); err != nil {\n    if strings.Contains(err.Error(), \"bind-recursive=writable' requires 'readonly'\") {\n        return fmt.Errorf(\"add 'readonly' to the mount spec when using bind-recursive=writable\")\n    }\n    return err\n}","preventionTips":["Always include 'readonly' or 'ro' when using 'bind-recursive=writable'.","Understand that 'writable' mode describes read-only mount behavior — it's meaningless without readonly.","Review the bind-recursive documentation before using advanced bind-mount options."],"tags":["mount","bind","validation","readonly"],"backgroundTag":null,"analyzedSha":"4f84911bfe8811e9b028e4b1fee8e7510be79387","analyzedAt":"2026-08-07T12:15:29.814Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}