hashicorp/nomad · warning

users: unable to parse uid/gid from username

Error message

users: unable to parse uid/gid from username

What it means

ErrCannotParse is returned by dynamic.Parse when a username does not match the expected dynamic-user naming pattern, or the embedded number fails to parse as a uint64 or exceeds math.MaxInt32. It indicates the name is not a valid dynamically-generated user.

Source

Thrown at helper/users/dynamic/pool.go:21

// Package dynamic provides a way of allocating UID/GID to be used by Nomad
// tasks with no associated service users managed by the operating system.
package dynamic

import (
	"errors"
	"math/rand"
	"strconv"
	"sync"

	"github.com/hashicorp/go-set/v3"
	"github.com/hashicorp/nomad/helper"
)

var (
	ErrPoolExhausted = errors.New("users: uid/gid pool exhausted")
	ErrReleaseUnused = errors.New("users: release of unused uid/gid")
	ErrCannotParse   = errors.New("users: unable to parse uid/gid from username")
)

// none indicates no dynamic user
const none = 0

// doNotEnable indicates functionality should be disabled
const doNotEnable = -1

// A UGID is a combination User (UID) and Group (GID). Since Nomad is
// allocating these values together from the same pool it can ensure they are
// always matching values, thus encoding them with one value.
type UGID int

// String returns the string representation of a UGID.
//
// It's just the numbers.
func (id UGID) String() string {
	return strconv.Itoa(int(id))

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Only call Parse on usernames produced by the dynamic user generator
  2. Check the username format (pattern + numeric suffix) before calling Parse
  3. Handle ErrCannotParse by treating the user as a non-dynamic/static user
  4. If IDs above MaxInt32 are expected on the platform, this check is a hard limit—regenerate the user within range

Example fix

// before: parse any user
gid, err := dynamic.Parse(username)
// after: skip non-dynamic users
if !strings.HasPrefix(username, dynamicUserPrefix) {
  return staticUserFallback
}
gid, err := dynamic.Parse(username)
if errors.Is(err, dynamic.ErrCannotParse) { return staticUserFallback }
Defensive patterns

Strategy: validation

Validate before calling

if !strings.HasPrefix(username, expectedPrefix) || !isDigits(username[len(expectedPrefix):]) {
  // not a dynamic user; skip Parse
}

Try / catch

gid, err := dynamic.Parse(user)
if errors.Is(err, dynamic.ErrCannotParse) {
  return handleStaticUser(user) // not a dynamic user
}

Prevention

When it happens

Trigger: Calling dynamic.Parse(user) with a username whose FindStringSubmatch does not yield exactly 2 groups (no numeric suffix), or whose numeric part overflows uint64 parsing or is greater than math.MaxInt32.

Common situations: Parsing usernames created outside the dynamic-user generator; OS account names changed manually; passing non-dynamic system users (e.g. root, nobody) to Parse; encountering legacy users with IDs above MaxInt32.

Understand the failure class

Related errors


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