{"record":{"id":"af0190d5f679533e","repo":"charmbracelet/crush","slug":"cannot-get-ownership-for-s-w","errorCode":null,"errorMessage":"cannot get ownership for %s: %w","messagePattern":"cannot get ownership for (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/fsext/lookup.go","lineNumber":273,"sourceCode":"\t}\n\treturn filepath.Clean(path)\n}\n\n// probeEnt checks if entity at given path exists and belongs to given owner\nfunc probeEnt(fspath string, owner int) error {\n\t_, err := os.Stat(fspath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot stat %s: %w\", fspath, err)\n\t}\n\n\t// special case for ownership check bypass\n\tif owner == -1 {\n\t\treturn nil\n\t}\n\n\tfowner, err := Owner(fspath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"cannot get ownership for %s: %w\", fspath, err)\n\t}\n\n\tif fowner != owner {\n\t\treturn os.ErrPermission\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":255,"sourceCodeEnd":282,"githubUrl":"https://github.com/charmbracelet/crush/blob/7944b8e52225d8805e31eacbf7ef24856b0dfb7a/internal/fsext/lookup.go#L255-L282","documentation":"After confirming the path exists, probeEnt queries the file's owner with fsext.Owner to enforce that lookups never cross ownership boundaries. This error wraps a failure of Owner(fspath) on an existing entity — usually a stat/ownership syscall failure on that specific path.","triggerScenarios":"The candidate file/dir exists but its owner cannot be determined: permission denied on the path itself despite existing (race where it became unreadable), failed mount, or an OS-level stat error between the initial os.Stat and the Owner check (TOCTOU).","commonSituations":"Files changing permissions mid-lookup (another process chmod'ing); FUSE/network filesystems flaking between two stat calls; security-hardened environments where stat on other users' files is blocked.","solutions":["Re-run the lookup; a transient race between the two stat calls usually resolves on retry","Check permissions/ownership of the specific path with `ls -la <path>` and `stat <path>`","Exclude unstable mounts (FUSE/NFS) from the lookup's starting directory","If persistent, verify the running user can stat all files in the search tree"],"exampleFix":"// before\nfound, err := fsext.Lookup(dir, target)\nif err != nil {\n    return err\n}\n// after — retry once on ownership-query failures\nfound, err := fsext.Lookup(dir, target)\nif err != nil && strings.Contains(err.Error(), \"cannot get ownership\") {\n    time.Sleep(50 * time.Millisecond)\n    found, err = fsext.Lookup(dir, target)\n}\nif err != nil {\n    return err\n}","handlingStrategy":"retry","validationCode":"// Ensure the runtime user can stat-and-read ownership of the search root\nvar st os.FileInfo\nvar err error\nif st, err = os.Stat(dir); err != nil {\n    return fmt.Errorf(\"search root unreadable: %w\", err)\n}\n_ = st\n","typeGuard":"func ownershipQueryable(path string) bool {\n    _, err := fsext.Owner(path)\n    return err == nil\n}","tryCatchPattern":"var found []string\nvar err error\nfor i := 0; i < 3; i++ {\n    found, err = fsext.Lookup(dir, targets...)\n    if err == nil || !strings.Contains(err.Error(), \"cannot get ownership\") {\n        break\n    }\n    time.Sleep(50 * time.Millisecond) // transient TOCTOU on mounts\n}\nif err != nil {\n    return err\n}","preventionTips":["Avoid running lookups while other processes chmod/chown the tree","Exclude flaky FUSE/NFS mounts from search roots","Prefer local disks for project directories the lookup walks","If it persists, check ACLs/LSM policies (SELinux) blocking stat on the file"],"tags":["filesystem","ownership","race-condition"],"backgroundTag":"ownership-check-failed","analyzedSha":"7944b8e52225d8805e31eacbf7ef24856b0dfb7a","analyzedAt":"2026-08-29T12:48:59.079Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}