hashicorp/nomad · error

cgroupslib: unable to update share cpuset with %q: %w

Error message

cgroupslib: unable to update share cpuset with %q: %w

What it means

partition.write() persists the dynamic share cpuset by writing the current set of shared cores to nomad.slice/share/cpuset.cpus (cgroups v2) when cores are reserved or released. This error wraps an os.WriteFile failure on that cpuset file, meaning the core partition state could not be synced to the kernel.

Source

Thrown at client/lib/cgroupslib/partition_linux.go:112

	return p.write()
}

func (p *partition) Release(cores *idset.Set[hw.CoreID]) error {

	p.lock.Lock()
	defer p.lock.Unlock()

	p.reserve.RemoveSet(cores)

	// Use the intersection with the usable cores to avoid removing more cores than available.
	p.share.InsertSet(p.usableCores.Intersect(cores))
	return p.write()
}

func (p *partition) write() error {
	shareStr := p.share.String()
	if err := os.WriteFile(p.sharePath, []byte(shareStr), 0644); err != nil {
		return fmt.Errorf("cgroupslib: unable to update share cpuset with %q: %w", shareStr, err)
	}

	reserveStr := p.reserve.String()
	if err := os.WriteFile(p.reservePath, []byte(reserveStr), 0644); err != nil {
		return fmt.Errorf("cgroupslib: unable to update reserve cpuset with %q: %w", reserveStr, err)
	}
	return nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Re-run cgroupslib Init to recreate the cgroup tree, then retry the Reserve/Release operation.
  2. Ensure the agent still has write access to /sys/fs/cgroup/nomad.slice/share/cpuset.cpus (root / delegation intact).
  3. Verify the share cpuset value is non-empty and within cpuset.cpus.effective; never reserve all cores, leaving share empty.
  4. If the error is EINVAL, check for kernel-isolated/offline cores excluded from the usable set.

Example fix

// before: reserving all cores empties share cpuset
err := partition.Reserve(allCores)
// after: keep at least one core in the share set
share := allCores.Diff(lastCore)
err := partition.Reserve(lastCore) // share keeps remaining cores
Defensive patterns

Strategy: retry

Validate before calling

func sharePathOK(p string) error {
  if _, err := os.Stat(p); err != nil { return err }
  return syscall.Access(p, syscall.W_OK)
}

Type guard

func shareCpusetValid(share *idset.Set[hw.CoreID], usable *idset.Set[hw.CoreID]) bool {
  return share != nil && !share.Intersect(usable).Empty()
}

Try / catch

if err := partition.Reserve(cores); err != nil {
  var perr *fs.PathError
  if errors.As(err, &perr) {
    // cgroup tree missing: re-init once, then retry
    if err := cgroupslib.Init(logger, coresStr); err != nil { return err }
    return partition.Reserve(cores)
  }
  return err
}

Prevention

When it happens

Trigger: os.WriteFile(p.sharePath, ...) fails during Reserve() or Release() — EACCES (lost cgroup write privileges), ENOENT (share cgroup directory removed or Init never ran), or EINVAL when the value is empty or contains cores outside the allowed parent cpuset.

Common situations: Releasing/reserving cores on a client whose cgroups were wiped (e.g. host rebooted and nomad.slice removed); Nomad process dropped privileges after startup; writing an empty core list after reserving all cores; manual deletion of share cgroup by an operator.

Related errors


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