projectdiscovery/katana · error
could not change ownership of chrome data directory
Error message
could not change ownership of chrome data directory
What it means
Thrown when os.Chown(tempDir, uid, gid) fails after the temp chrome data directory was created for ChromeUser. Katana removes the directory and aborts because Chrome would otherwise run with the wrong profile ownership. Typical causes are the process lacking CAP_CHOWN/root privileges or a nonexistent uid/gid pair.
Source
Thrown at pkg/engine/headless/browser/browser.go:401
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 = true
}
}
browser, err := l.launchBrowserWithDataDir(tempDir)
if err != nil {
if shouldCleanupTempDir {
_ = os.RemoveAll(tempDir)
}
return nil, errView on GitHub (pinned to e3e742739c)
Solutions
- Run the process as root or with CAP_CHOWN when ChromeUser ownership change is required (Docker --user root or securityContext capabilities).
- Prefer running the process itself as the chrome user so no chown to a foreign uid is needed.
- Verify the uid/gid exist: getent passwd <uid>; getent group <gid>.
- Ensure the filesystem backing the temp dir supports chown and the parent directory is writable.
- If a dedicated user is unnecessary, set ChromeUser=nil to skip the chown path entirely.
Example fix
// before # k8s pod running as 1000, ChromeUser uid 998 -> chown denied // after securityContext: runAsUser: 998 runAsGroup: 998
Defensive patterns
Strategy: validation
Validate before calling
u := opts.ChromeUser
uid, _ := strconv.Atoi(u.Uid)
if os.Geteuid() != 0 && os.Geteuid() != uid {
return fmt.Errorf("cannot chown to %s:%s: run as root or as uid %d", u.Uid, u.Gid, uid)
} Type guard
func canChownTo(uid int) bool {
return os.Geteuid() == 0 || os.Geteuid() == uid
} Try / catch
page, err := l.createBrowserPageFunc(...)
if err != nil && strings.Contains(err.Error(), "change ownership of chrome data directory") {
l.opts.ChromeUser = nil // retry without ownership change
page, err = l.createBrowserPageFunc(...)
} Prevention
- Grant CAP_CHOWN or run as root only if chown is genuinely required.
- Prefer running the process itself as the chrome user instead of chowning afterwards.
- Verify target uid/gid exist with getent before launch.
- Remember container user-namespace remapping shifts uid validity.
When it happens
Trigger: ChromeUser set with a uid/gid the current process may not chown to: not running as root and target uid != current uid, target uid/gid does not exist, or an immutable/read-only filesystem.
Common situations: Docker/Kubernetes containers without root or CAP_CHOWN while using a dedicated chrome user; user-namespace remapping making the uid invalid; running katana as a non-root user for a different chrome user.
Related errors
- could not create temporary chrome data directory
- could not create graph file
- invalid user ID
- invalid group ID
- could not create new page
AI-assisted analysis of projectdiscovery/katana@e3e742739c (2026-09-03).
Data as JSON: /api/errors/d63f9f4127a5fb66.
Report an issue: GitHub.