projectdiscovery/katana · error
invalid user ID
Error message
invalid user ID
What it means
Thrown when strconv.Atoi fails to parse ChromeUser.Uid. Katana needs the UID as an integer to os.Chown the freshly created temp chrome data directory. The temp dir is removed before returning to avoid leaking stale profile data.
Source
Thrown at pkg/engine/headless/browser/browser.go:392
var tempDir string
shouldCleanupTempDir := false
if l.opts.ChromeWSUrl == "" {
if l.opts.UserDataDir != "" {
// Use user-provided data directory (preserve sessions/cookies)
tempDir = l.opts.UserDataDir
shouldCleanupTempDir = false
} else if l.opts.ChromeUser != nil {
var err error
tempDir, err = os.MkdirTemp(l.opts.ChromeUser.HomeDir, "chrome-data-*")
if err != nil {
return nil, errors.Wrap(err, "could not create temporary chrome data directory")
}
uid, err := strconv.Atoi(l.opts.ChromeUser.Uid)
if err != nil {
_ = os.RemoveAll(tempDir)
return nil, errors.Wrap(err, "invalid user ID")
}
gid, err := strconv.Atoi(l.opts.ChromeUser.Gid)
if err != nil {
_ = os.RemoveAll(tempDir)
return nil, errors.Wrap(err, "invalid group ID")
}
if err := os.Chown(tempDir, uid, gid); err != nil {
_ = os.RemoveAll(tempDir)
return nil, errors.Wrap(err, "could not change ownership of chrome data directory")
}
shouldCleanupTempDir = true
} else {
var err error
tempDir, err = os.MkdirTemp("", "katana-chrome-data-*")
if err != nil {
return nil, errors.Wrap(err, "could not create temporary chrome data directory")
}
shouldCleanupTempDir = trueView on GitHub (pinned to e3e742739c)
Solutions
- Populate ChromeUser via user.Lookup("chrome"), which fills Uid as a decimal string, instead of building the struct by hand.
- Validate before use: if _, err := strconv.Atoi(u.Uid); err != nil fall back to ChromeUser=nil.
- Check /etc/passwd (or the NSS backend) that the account has a numeric UID; fix the directory service entry if empty.
- If no ownership change is needed, leave ChromeUser nil so katana uses the default temp dir path.
Example fix
// before
opts.ChromeUser = &user.User{Username: "chrome", HomeDir: "/home/chrome"} // Uid empty
// after
u, err := user.Lookup("chrome")
if err != nil {
return err
}
opts.ChromeUser = u Defensive patterns
Strategy: validation
Validate before calling
if opts.ChromeUser != nil {
if _, err := strconv.Atoi(opts.ChromeUser.Uid); err != nil {
return fmt.Errorf("ChromeUser.Uid %q is not numeric", opts.ChromeUser.Uid)
}
} Type guard
func hasNumericID(u *user.User) bool {
_, uidErr := strconv.Atoi(u.Uid)
_, gidErr := strconv.Atoi(u.Gid)
return uidErr == nil && gidErr == nil
} Try / catch
page, err := l.createBrowserPageFunc(...)
if err != nil && strings.Contains(err.Error(), "invalid user ID") {
l.opts.ChromeUser = nil // retry without dedicated chrome user
page, err = l.createBrowserPageFunc(...)
} Prevention
- Always populate ChromeUser via os/user Lookup rather than hand-built structs.
- Validate Uid/Gid with strconv.Atoi immediately after lookup.
- Guard against directory services (LDAP/SSSD) returning empty numeric IDs.
- Default to ChromeUser=nil when ownership isolation is not needed.
When it happens
Trigger: ChromeUser.Uid is not a valid decimal integer string — empty ("") or non-numeric — typically when the *user.User struct was constructed manually or came from a directory service that did not populate Uid.
Common situations: Hand-built user.User{Username: "chrome"} without Uid; LDAP/SSSD/NSS lookups returning incomplete entries; populating Uid with a username instead of a number; unusual passwd formats.
Related errors
- invalid group ID
- unsupported strategy
- could not create temporary chrome data directory
- could not change ownership of chrome data directory
- could not create new page
AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03).
Data as JSON: /api/errors/0cf14f22fcc88b98.
Report an issue: GitHub.