docker/cli · error
option 'bind-recursive=readonly' requires…
Error message
option 'bind-recursive=readonly' requires 'bind-propagation=rprivate' to be specified in conjunction
What it means
Returned by validateMountOptions (opts/mount_utils.go:32) when BindOptions.ReadOnlyForceRecursive is true ('bind-recursive=readonly') and m.ReadOnly is true, but bind propagation is not set to 'rprivate'. Recursively read-only bind mounts require rprivate propagation to prevent mount events from propagating into the read-only subtree. Note: there is a FIXME in the code indicating daemon-side validation for this constraint is currently missing.
Solutions
- Add 'bind-propagation=rprivate' to the --mount spec when using 'bind-recursive=readonly'.
- Ensure no conflicting 'bind-propagation' value is set; remove it if present so rprivate can be used.
Example fix
// before: missing rprivate propagation // docker run --mount type=bind,src=/x,dst=/y,readonly,bind-recursive=readonly nginx // after: add rprivate propagation // docker run --mount type=bind,src=/x,dst=/y,readonly,bind-recursive=readonly,bind-propagation=rprivate nginx
Defensive patterns
Strategy: validation
Validate before calling
func validateRecursiveReadonlyPropagation(spec string) error {
if strings.Contains(spec, "bind-recursive=readonly") {
if !strings.Contains(spec, "bind-propagation=rprivate") {
return fmt.Errorf("bind-recursive=readonly requires bind-propagation=rprivate")
}
}
return nil
} Try / catch
if err := mountOpt.Set(value); err != nil {
if strings.Contains(err.Error(), "bind-recursive=readonly' requires 'bind-propagation=rprivate'") {
return fmt.Errorf("add 'bind-propagation=rprivate' to the mount spec when using bind-recursive=readonly")
}
return err
} Prevention
- Always include 'bind-propagation=rprivate' when using 'bind-recursive=readonly'.
- Ensure no conflicting 'bind-propagation' value is set alongside bind-recursive=readonly.
- Be aware that daemon-side validation for this constraint is currently missing (per FIXME in source).
When it happens
Trigger: A --mount value includes 'bind-recursive=readonly' and 'readonly' but either omits 'bind-propagation=rprivate' or sets a different propagation. For example: '--mount type=bind,src=/x,dst=/y,readonly,bind-recursive=readonly' (propagation defaults to something other than rprivate).
Common situations: Using 'bind-recursive=readonly' without understanding that the kernel's recursively-read-only feature requires rprivate propagation to be safe, or setting a different propagation value that conflicts with the requirement.
Related errors
- option 'bind-recursive=writable' requires 'readonly' to be…
- option 'bind-recursive=readonly' requires 'readonly' to be…
- bind options are incompatible with type volume
- bind options are incompatible with type image
- invalid value for : (must be "enabled", "disabled"…
AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07).
Data as JSON: /api/errors/5dd563038c0031bf.
Report an issue: GitHub.
Appendix: source
Thrown at opts/mount_utils.go:32
func validateMountOptions(m *mount.Mount) error {
if err := validateExclusiveOptions(m); err != nil {
return err
}
if m.BindOptions != nil {
if m.BindOptions.ReadOnlyNonRecursive && !m.ReadOnly {
return errors.New("option 'bind-recursive=writable' requires 'readonly' to be specified in conjunction")
}
if m.BindOptions.ReadOnlyForceRecursive {
if !m.ReadOnly {
return errors.New("option 'bind-recursive=readonly' requires 'readonly' to be specified in conjunction")
}
if m.BindOptions.Propagation != mount.PropagationRPrivate {
// FIXME(thaJeztah): this is missing daemon-side validation
//
// docker run --rm --mount type=bind,src=/var/run,target=/foo,bind-recursive=readonly,readonly alpine
// # no error
return errors.New("option 'bind-recursive=readonly' requires 'bind-propagation=rprivate' to be specified in conjunction")
}
}
}
return nil
}
// validateExclusiveOptions checks if the given mount config only contains
// options for the given mount-type.
//
// This is the client-side equivalent of [mounts.validateExclusiveOptions] in
// the daemon, but with error-messages matching client-side flags / options.
//
// [mounts.validateExclusiveOptions]: https://github.com/moby/moby/blob/v2.0.0-beta.6/daemon/volume/mounts/validate.go#L31-L50
func validateExclusiveOptions(m *mount.Mount) error {
if m.Type == "" {
return errors.New("type is required")
}View on GitHub (pinned to 4f84911bfe)