{"record":{"id":"42aa09831451fad3","repo":"hashicorp/nomad","slug":"users-unable-to-parse-uid-gid-from-username","errorCode":null,"errorMessage":"users: unable to parse uid/gid from username","messagePattern":"users: unable to parse uid/gid from username","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"helper/users/dynamic/pool.go","lineNumber":21,"sourceCode":"\n// Package dynamic provides a way of allocating UID/GID to be used by Nomad\n// tasks with no associated service users managed by the operating system.\npackage dynamic\n\nimport (\n\t\"errors\"\n\t\"math/rand\"\n\t\"strconv\"\n\t\"sync\"\n\n\t\"github.com/hashicorp/go-set/v3\"\n\t\"github.com/hashicorp/nomad/helper\"\n)\n\nvar (\n\tErrPoolExhausted = errors.New(\"users: uid/gid pool exhausted\")\n\tErrReleaseUnused = errors.New(\"users: release of unused uid/gid\")\n\tErrCannotParse   = errors.New(\"users: unable to parse uid/gid from username\")\n)\n\n// none indicates no dynamic user\nconst none = 0\n\n// doNotEnable indicates functionality should be disabled\nconst doNotEnable = -1\n\n// A UGID is a combination User (UID) and Group (GID). Since Nomad is\n// allocating these values together from the same pool it can ensure they are\n// always matching values, thus encoding them with one value.\ntype UGID int\n\n// String returns the string representation of a UGID.\n//\n// It's just the numbers.\nfunc (id UGID) String() string {\n\treturn strconv.Itoa(int(id))","sourceCodeStart":3,"sourceCodeEnd":39,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/helper/users/dynamic/pool.go#L3-L39","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before: parse any user\ngid, err := dynamic.Parse(username)\n// after: skip non-dynamic users\nif !strings.HasPrefix(username, dynamicUserPrefix) {\n  return staticUserFallback\n}\ngid, err := dynamic.Parse(username)\nif errors.Is(err, dynamic.ErrCannotParse) { return staticUserFallback }","handlingStrategy":"validation","validationCode":"if !strings.HasPrefix(username, expectedPrefix) || !isDigits(username[len(expectedPrefix):]) {\n  // not a dynamic user; skip Parse\n}","typeGuard":null,"tryCatchPattern":"gid, err := dynamic.Parse(user)\nif errors.Is(err, dynamic.ErrCannotParse) {\n  return handleStaticUser(user) // not a dynamic user\n}","preventionTips":["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)"],"tags":["go","parsing","nomad","users"],"backgroundTag":"username-parse-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}