{"record":{"id":"2d6bd0c1b22d3026","repo":"wagoodman/dive","slug":"unable-to-open-file-q-s","errorCode":null,"errorMessage":"unable to open file %q: %s","messagePattern":"unable to open file %q: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"dive/filetree/file_info.go","lineNumber":72,"sourceCode":"\t\tfileType = tar.TypeSymlink\n\n\t\tlinkName, err = os.Readlink(realPath)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Errorf(\"unable to read symlink %q: %s\", realPath, err))\n\t\t}\n\t} else if info.IsDir() {\n\t\tfileType = tar.TypeDir\n\t} else {\n\t\tfileType = tar.TypeReg\n\n\t\tsize = info.Size()\n\t}\n\n\tvar hash uint64\n\tif fileType != tar.TypeDir {\n\t\tfile, err := os.Open(realPath)\n\t\tif err != nil {\n\t\t\tpanic(fmt.Errorf(\"unable to open file %q: %s\", realPath, err))\n\t\t}\n\t\tdefer file.Close()\n\t\thash = getHashFromReader(file)\n\t}\n\n\treturn FileInfo{\n\t\tPath:     path,\n\t\tTypeFlag: fileType,\n\t\tLinkname: linkName,\n\t\thash:     hash,\n\t\tSize:     size,\n\t\tMode:     info.Mode(),\n\t\t// todo: support UID/GID\n\t\tUid:   -1,\n\t\tGid:   -1,\n\t\tIsDir: info.IsDir(),\n\t}\n}","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/wagoodman/dive/blob/d6c691947f8fda635c952a17ee3b7555379d58f0/dive/filetree/file_info.go#L54-L90","documentation":"Raised as a panic in NewFileInfoFromPath (dive/filetree/file_info.go:72). For every non-directory entry the function opens the file with os.Open(realPath) to hash its contents; if the open fails, the library panics with 'unable to open file %q: %s'. Hashing is mandatory for regular files, so any open failure aborts the process.","triggerScenarios":"File deleted, renamed, or chmod'd between the walk's lstat and dive's os.Open (race); file with mode 000 or otherwise unreadable by the effective user; a FIFO/socket/device that opens but behaves oddly; path longer than PATH_MAX on some filesystems.","commonSituations":"Scanning a live container overlay or build output directory that changes mid-scan, scanning files owned by another user without root, and scanning directories containing sockets/FIFOs created by running daemons.","solutions":["Make the tree static before analysis: stop the writing process, or copy/snapshot the directory first (cp -a / rsync) and scan the copy","Check permissions on the failing path: ls -l <path>; fix ownership or run dive as a user that can read it","Prune volatile/unreadable subtrees from the walk","As a library consumer, pre-check readability with os.Open before calling NewFileInfoFromPath and skip unreadable entries"],"exampleFix":"// before: assume every regular file is openable\nfi := filetree.NewFileInfoFromPath(p, real, info) // panics if open fails\n\n// after: gate on an explicit readability probe\nif info.Mode().IsRegular() {\n    f, err := os.Open(real)\n    if err != nil {\n        log.Printf(\"skipping unreadable file %s: %v\", real, err)\n        return nil\n    }\n    f.Close()\n}\nfi := filetree.NewFileInfoFromPath(p, real, info)","handlingStrategy":"validation","validationCode":"// probe readability before hashing path\nfunc openable(realPath string, info os.FileInfo) bool {\n    if !info.Mode().IsRegular() {\n        return true // dirs are never opened\n    }\n    f, err := os.Open(realPath)\n    if err != nil {\n        return false\n    }\n    f.Close()\n    return true\n}\n\nif !openable(realPath, info) {\n    return nil // skip unreadable file instead of panicking\n}","typeGuard":null,"tryCatchPattern":"// recover-based guard for library consumers driving their own walk:\ndefer func() {\n    if r := recover(); r != nil {\n        log.Printf(\"skipping %s: %v\", realPath, r)\n    }\n}()\nfi := filetree.NewFileInfoFromPath(path, realPath, info)","preventionTips":["Analyze a snapshot of the tree, never a live build directory","Fix ownership/modes (chmod -R u+r or run with privilege) before scanning","Prune sockets, FIFOs, and files owned by other users from the walk root"],"tags":["filesystem","panic","permissions","race-condition","hashing"],"backgroundTag":null,"analyzedSha":"d6c691947f8fda635c952a17ee3b7555379d58f0","analyzedAt":"2026-08-15T09:42:35.293Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}