hashicorp/nomad · error

failed to open current netns: %v

Error message

failed to open current netns: %v

What it means

Inside netNS.Do(), after switching into the target namespace, the code calls GetCurrentNS() to capture the current (contained) namespace to switch back to later. This error wraps a failure of GetCurrentNS() at that point, meaning the thread could not open a handle to its own (new) network namespace.

Source

Thrown at client/lib/nsutil/ns_linux.go:182

	return ns.file.Fd()
}

func (ns *netNS) errorIfClosed() error {
	if ns.closed {
		return fmt.Errorf("%q has already been closed", ns.file.Name())
	}
	return nil
}

func (ns *netNS) Do(toRun func(NetNS) error) error {
	if err := ns.errorIfClosed(); err != nil {
		return err
	}

	containedCall := func(hostNS NetNS) error {
		threadNS, err := GetCurrentNS()
		if err != nil {
			return fmt.Errorf("failed to open current netns: %v", err)
		}
		defer threadNS.Close()

		// switch to target namespace
		if err = ns.Set(); err != nil {
			return fmt.Errorf("error switching to ns %v: %v", ns.file.Name(), err)
		}
		defer func() {
			err := threadNS.Set() // switch back
			if err == nil {
				// Unlock the current thread only when we successfully switched back
				// to the original namespace; otherwise leave the thread locked which
				// will force the runtime to scrap the current thread, that is maybe
				// not as optimal but at least always safe to do.
				runtime.UnlockOSThread()
			}
		}()

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure /proc is mounted inside the environment where Do() runs
  2. Check and raise the process fd limit (ulimit -n) — opening the ns adds descriptors
  3. Run with sufficient privileges (CAP_SYS_ADMIN) to open namespace files
  4. Verify /proc/self/ns/net is readable; test with os.Open in isolation
  5. Inspect the wrapped error from GetCurrentNS for the exact errno

Example fix

// before
threadNS, err := GetCurrentNS()
if err != nil {
    return fmt.Errorf("failed to open current netns: %v", err) // EMFILE
}
// after
if err := raiseFdLimit(); err != nil {
    return fmt.Errorf("cannot raise fd limit: %w", err)
}
threadNS, err := GetCurrentNS()
if err != nil {
    return fmt.Errorf("failed to open current netns: %w", err)
}
Defensive patterns

Strategy: validation

Validate before calling

func precheckNetnsEnv() error {
    if _, err := os.Stat("/proc/self/ns/net"); err != nil {
        return fmt.Errorf("/proc/self/ns/net unavailable: %w", err)
    }
    var l syscall.Rlimit
    if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &l); err == nil && l.Cur < 1024 {
        return fmt.Errorf("fd limit low: %d", l.Cur)
    }
    return nil
}

Try / catch

ns.Do(func(hostNS NetNS) error {
    // work
    return nil
})
// on error:
if err != nil && strings.Contains(err.Error(), "failed to open current netns") {
    return fmt.Errorf("cannot open contained ns; check /proc mount and fd limit: %w", err)
}

Prevention

When it happens

Trigger: GetCurrentNS() failing inside the containedCall closure of Do() — typically because /proc/self/ns/net (via the thread's ns path) cannot be opened: /proc not mounted, fd exhaustion (EMFILE), or permission problems in the contained environment.

Common situations: Running inside a container with no /proc mounted; the process hit its file-descriptor limit after opening the target ns; a restricted environment where /proc/self/ns/net is not accessible.

Related errors


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