hashicorp/nomad · error

error from unshare: %v

Error message

error from unshare: %v

What it means

After saving the original namespace, NewNS calls unix.Unshare(CLONE_NEWNET) on the locked thread to create a fresh network namespace. If the kernel rejects the unshare, the error is wrapped as 'error from unshare'. This means the process lacks the privileges or the kernel disallows creating a new network namespace at that point.

Source

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

	// the caller of this function
	go (func() {
		defer wg.Done()
		runtime.LockOSThread()
		// Don't unlock. By not unlocking, golang will kill the OS thread when the
		// goroutine is done (for go1.10+)

		var origNS NetNS
		origNS, err = GetNS(getCurrentThreadNetNSPath())
		if err != nil {
			err = fmt.Errorf("failed to get the current netns: %v", err)
			return
		}
		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)

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Run the program with CAP_SYS_ADMIN or as root (or via a setuid helper)
  2. Enable unprivileged namespace creation: sysctl -w kernel.unprivileged_userns_clone=1 (distro-dependent)
  3. Raise user namespace limits: check/raise /proc/sys/user/max_user_namespaces
  4. Confirm the kernel is compiled with CONFIG_NET_NS=y

Example fix

// before: EPERM from unshare in unprivileged container
// after:
// docker run --cap-add NET_ADMIN --cap-add SYS_ADMIN myimage
ns, err := nsutil.NewNS()
Defensive patterns

Strategy: try-catch

Validate before calling

out, _ := exec.Command("unshare", "-n", "true").CombinedOutput()
if out != nil || execErr != nil {
    return errors.New("this environment cannot create network namespaces (need CAP_SYS_ADMIN or userns)")
}

Try / catch

ns, err := nsutil.NewNS()
if err != nil && strings.Contains(err.Error(), "error from unshare") {
    if errors.Is(err, os.ErrPermission) {
        return fmt.Errorf("missing CAP_SYS_ADMIN for unshare(CLONE_NEWNET): %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: unix.Unshare(CLONE_NEWNET) returns an error during NewNS — EPERM because the process lacks CAP_SYS_ADMIN, or failure because namespace limits (max_user_namespaces) are exhausted.

Common situations: Unprivileged users without user namespaces enabled (kernel.unprivileged_userns_clone=0); containers without CAP_SYS_ADMIN; exhausted user.max_net_namespaces limits on multi-tenant hosts.

Related errors


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