hashicorp/nomad · error

mount --make-rshared %s failed: %q

Error message

mount --make-rshared %s failed: %q

What it means

NewNS creates a new network namespace and bind-mounts it under /var/run/netns so it persists. Before creating the namespace, it tries to remount the netns directory as shared; if that Mount fails with anything other than EINVAL (meaning the dir is not a mountpoint), the library wraps and returns this error. It indicates the kernel refused the recursive shared remount of /var/run/netns.

Source

Thrown at client/lib/nsutil/netns_linux.go:53

// NewNS creates a new persistent (bind-mounted) network namespace and returns
// an object representing that namespace, without switching to it.
func NewNS(nsName string) (NetNS, error) {

	// Create the directory for mounting network namespaces
	// This needs to be a shared mountpoint in case it is mounted in to
	// other namespaces (containers)
	err := os.MkdirAll(NetNSRunDir, 0755)
	if err != nil {
		return nil, err
	}

	// Remount the namespace directory shared. This will fail if it is not
	// already a mountpoint, so bind-mount it on to itself to "upgrade" it
	// to a mountpoint.
	err = unix.Mount("", NetNSRunDir, "none", unix.MS_SHARED|unix.MS_REC, "")
	if err != nil {
		if err != unix.EINVAL {
			return nil, fmt.Errorf("mount --make-rshared %s failed: %q", NetNSRunDir, err)
		}

		// Recursively remount /var/run/netns on itself. The recursive flag is
		// so that any existing netns bindmounts are carried over.
		err = unix.Mount(NetNSRunDir, NetNSRunDir, "none", unix.MS_BIND|unix.MS_REC, "")
		if err != nil {
			return nil, fmt.Errorf("mount --rbind %s %s failed: %q", NetNSRunDir, NetNSRunDir, err)
		}

		// Now we can make it shared
		err = unix.Mount("", NetNSRunDir, "none", unix.MS_SHARED|unix.MS_REC, "")
		if err != nil {
			return nil, fmt.Errorf("mount --make-rshared %s failed: %q", NetNSRunDir, err)
		}

	}

	// create an empty file at the mount point

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the process runs with CAP_SYS_ADMIN (e.g. docker run --privileged or add SYS_ADMIN capability) since creating netns requires it
  2. Verify /var/run/netns exists and is a mountpoint: mkdir -p /var/run/netns && mount --bind /var/run/netns /var/run/netns
  3. If running in a container, ensure it is not blocked by seccomp/apparmor; use --security-opt seccomp=unconfined for testing
  4. Check /var/run is a symlink to /run and both paths are consistent

Example fix

// before (inside unprivileged container, fails)
ns, err := nsutil.NewNS()
// after: grant capability at deploy time
// docker run --cap-add SYS_ADMIN -v /run/netns:/run/netns:shared myimage
ns, err := nsutil.NewNS()
Defensive patterns

Strategy: validation

Validate before calling

if _, err := os.Stat("/run/netns"); err != nil { os.MkdirAll("/run/netns", 0755) }
if err := unix.Mount("", "/run/netns", "", unix.MS_SHARED|unix.MS_REC, ""); err != nil && err != unix.EINVAL {
    return fmt.Errorf("environment cannot make /run/netns shared: %v", err)
}

Type guard

func canCreateNetns() bool {
    return unix.Eaccess == nil // placeholder; check capability instead:
}
func hasCapSysAdmin() bool {
    hdr, _ := os.ReadFile("/proc/self/status")
    return strings.Contains(string(hdr), "CapEff") && capEnabled(string(hdr))
}

Try / catch

ns, err := nsutil.NewNS()
if err != nil && strings.Contains(err.Error(), "make-rshared") {
    return fmt.Errorf("netns mount propagation unavailable (need CAP_SYS_ADMIN): %w", err)
}

Prevention

When it happens

Trigger: unix.Mount("", NetNSRunDir, "none", MS_SHARED|MS_REC) fails with a non-EINVAL error while NewNS runs (invoked via CreateNetwork). Happens when /var/run/netns exists but the mount syscall is rejected for reasons other than 'not a mountpoint' (e.g. EPERM in restricted containers, ENOENT if the dir vanished).

Common situations: Running inside unprivileged containers or sandboxes (Docker without CAP_SYS_ADMIN, gVisor, user-namespace restrictions) where mount() is denied; /var/run/netns removed concurrently; seccomp profiles blocking mount.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/dea7d82b1b5c0067. Report an issue: GitHub.