hashicorp/nomad · error
failed to bind mount ns at %s: %v
Error message
failed to bind mount ns at %s: %v
What it means
After unsharing, NewNS bind-mounts the thread's new namespace from /proc/<tid>/ns/net onto a persistent file under /var/run/netns. If that mount fails, this message wraps it and NewNS ultimately returns 'failed to create namespace'. The mount is what keeps the namespace alive after the thread exits.
Source
Thrown at client/lib/nsutil/netns_linux.go:119
}
defer origNS.Close()
// create a new netns on the current thread
err = unix.Unshare(unix.CLONE_NEWNET)
if err != nil {
err = fmt.Errorf("error from unshare: %v", err)
return
}
// Put this thread back to the orig ns, since it might get reused (pre go1.10)
defer origNS.Set()
// bind mount the netns from the current thread (from /proc) onto the
// mount point. This causes the namespace to persist, even when there
// are no threads in the ns.
err = unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", unix.MS_BIND, "")
if err != nil {
err = fmt.Errorf("failed to bind mount ns at %s: %v", nsPath, err)
}
})()
wg.Wait()
if err != nil {
return nil, fmt.Errorf("failed to create namespace: %v", err)
}
return GetNS(nsPath)
}
// UnmountNS unmounts the NS held by the netns object
func UnmountNS(nsPath string) error {
// Only unmount if it's been bind-mounted (don't touch namespaces in /proc...)
if strings.HasPrefix(nsPath, NetNSRunDir) {
if err := unix.Unmount(nsPath, unix.MNT_DETACH); err != nil {
return fmt.Errorf("failed to unmount NS: at %s: %w", nsPath, err)
}View on GitHub (pinned to 482b49bf1a)
Solutions
- Ensure /var/run/netns is a shared mount: mount --bind /run/netns /run/netns && mount --make-shared /run/netns
- Confirm the empty target file exists and is writable before the mount (library creates it; check disk/state)
- Grant CAP_SYS_ADMIN to the process
- Check /run is writable and has space
Example fix
// before: /run/netns lost its shared mount after container restart // after (entrypoint): // mount --make-shared /run/netns || true ns, err := nsutil.NewNS()
Defensive patterns
Strategy: validation
Validate before calling
if err := unix.Mount("", "/run/netns", "", unix.MS_SHARED|unix.MS_REC, ""); err != nil && err != unix.EINVAL {
return fmt.Errorf("/run/netns not prepared for ns bind-mount: %v", err)
}
if unix.Access("/run/netns", unix.W_OK) != nil {
return errors.New("/run/netns is not writable")
} Try / catch
ns, err := nsutil.NewNS()
if err != nil && strings.Contains(err.Error(), "failed to bind mount ns") {
return fmt.Errorf("could not persist netns under /run/netns; check it is a shared writable mount: %w", err)
} Prevention
- Ensure /run/netns is a shared, writable bind mount in every container instance
- Re-apply 'mount --make-shared /run/netns' in entrypoints (propagation resets on restart)
- Keep /run writable and monitor free space
- Grant CAP_SYS_ADMIN so MS_BIND mounts succeed
When it happens
Trigger: unix.Mount(getCurrentThreadNetNSPath(), nsPath, "none", MS_BIND) fails during NewNS — e.g. the target file under /var/run/netns could not be used as a mountpoint (not created, wrong fs) or mount is denied (EPERM).
Common situations: /var/run/netns not a shared mount (propagation lost after container restart); read-only /run; antivirus/security software interfering with mounts; leftover stale files with the target name.
Related errors
- mount --rbind %s %s failed: %q
- mount --make-rshared %s failed: %q
- Failed to unmount proc %q: %w
- failed to get the current netns: %v
- error from unshare: %v
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/501c94503a108b02.
Report an issue: GitHub.