wagoodman/dive · error
unable to open file %q: %s
Error message
unable to open file %q: %s
What it means
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.
Source
Thrown at dive/filetree/file_info.go:72
fileType = tar.TypeSymlink
linkName, err = os.Readlink(realPath)
if err != nil {
panic(fmt.Errorf("unable to read symlink %q: %s", realPath, err))
}
} else if info.IsDir() {
fileType = tar.TypeDir
} else {
fileType = tar.TypeReg
size = info.Size()
}
var hash uint64
if fileType != tar.TypeDir {
file, err := os.Open(realPath)
if err != nil {
panic(fmt.Errorf("unable to open file %q: %s", realPath, err))
}
defer file.Close()
hash = getHashFromReader(file)
}
return FileInfo{
Path: path,
TypeFlag: fileType,
Linkname: linkName,
hash: hash,
Size: size,
Mode: info.Mode(),
// todo: support UID/GID
Uid: -1,
Gid: -1,
IsDir: info.IsDir(),
}
}View on GitHub (pinned to d6c691947f)
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
Example fix
// before: assume every regular file is openable
fi := filetree.NewFileInfoFromPath(p, real, info) // panics if open fails
// after: gate on an explicit readability probe
if info.Mode().IsRegular() {
f, err := os.Open(real)
if err != nil {
log.Printf("skipping unreadable file %s: %v", real, err)
return nil
}
f.Close()
}
fi := filetree.NewFileInfoFromPath(p, real, info) Defensive patterns
Strategy: validation
Validate before calling
// probe readability before hashing path
func openable(realPath string, info os.FileInfo) bool {
if !info.Mode().IsRegular() {
return true // dirs are never opened
}
f, err := os.Open(realPath)
if err != nil {
return false
}
f.Close()
return true
}
if !openable(realPath, info) {
return nil // skip unreadable file instead of panicking
} Try / catch
// recover-based guard for library consumers driving their own walk:
defer func() {
if r := recover(); r != nil {
log.Printf("skipping %s: %v", realPath, r)
}
}()
fi := filetree.NewFileInfoFromPath(path, realPath, info) Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- unable to read symlink %q: %s
- unable to read file: %w
- cannot open export file: %w
- failed to read CI config file %s: %w
- unable to write to hash: %w
AI-assisted analysis of wagoodman/dive@d6c691947f (2026-08-15).
Data as JSON: /api/errors/2d6bd0c1b22d3026.
Report an issue: GitHub.