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
- Only call Parse on usernames produced by the dynamic user generator
- Check the username format (pattern + numeric suffix) before calling Parse
- Handle ErrCannotParse by treating the user as a non-dynamic/static user
- 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
- Only Parse usernames generated by the dynamic user feature
- Treat ErrCannotParse as 'not a dynamic user', not a hard failure
- Do not attempt to parse users with IDs above math.MaxInt32
- Keep usernames in their generated form (no manual renames)
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Unable to convert Uid to an int: %w
- Unable to convert Gid to an int: %w
- must pass non-nil job
- job is missing ID
- ErrLockConflict
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/42aa09831451fad3.
Report an issue: GitHub.