hashicorp/nomad · info

Failed to close %q: %v

Error message

Failed to close %q: %v

What it means

netNS wraps an *os.File pointing at the namespace; Close closes that file handle. If the underlying file close fails, the library reports 'Failed to close <path>'. This is uncommon on Linux but indicates the descriptor could not be released cleanly.

Source

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

	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	return GetNS(getCurrentThreadNetNSPath())
}

func getCurrentThreadNetNSPath() string {
	// /proc/self/ns/net returns the namespace of the main thread, not
	// of whatever thread this goroutine is running on.  Make sure we
	// use the thread's net namespace since the thread is switching around
	return fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), unix.Gettid())
}

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

	if err := ns.file.Close(); err != nil {
		return fmt.Errorf("Failed to close %q: %v", ns.file.Name(), err)
	}
	ns.closed = true

	return nil
}

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

	if err := unix.Setns(int(ns.Fd()), unix.CLONE_NEWNET); err != nil {
		return fmt.Errorf("Error switching to ns %v: %v", ns.file.Name(), err)
	}

	return nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Call Close exactly once per netns handle and rely on the closed flag for idempotency
  2. Do not close the underlying fd from elsewhere (avoid sharing the *os.File outside the library)
  3. Check for fd leaks/tampering if EBADF appears; audit any code that duplicates or reaps fds
  4. If this surfaces in tests, ensure teardown order does not close the ns before the library does

Example fix

// before: double close
ns.Close()
err := ns.Close() // already-closed error path
// after: close once, defer handles it
func work(ns nsutil.NetNS) error {
    defer ns.Close()
    return nil
}
Defensive patterns

Strategy: try-catch

Type guard

func isNetnsOpen(ns nsutil.NetNS) bool { return ns != nil && !ns.IsClosed() }

Try / catch

if err := ns.Close(); err != nil {
    log.Printf("warn: netns close failed for handle: %v (possible double-close or external fd close)", err)
}

Prevention

When it happens

Trigger: Calling ns.Close() (also invoked via deferred cleanup in NewNS) when ns.file.Close() returns an error — e.g. the file was already closed at the fd level, I/O error, or fd closed elsewhere causing EBADF. Note Close returns errorIfClosed's error first if called twice.

Common situations: Calling Close twice on the same netns handle (second call returns 'netns already closed', not this error); external code closing the same fd; resource-limit related edge cases during heavy churn of namespaces.

Related errors


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