{"record":{"id":"efe96d42aa51a22f","repo":"dagger/dagger","slug":"unexpected-stat-type-t-efe96d","errorCode":null,"errorMessage":"unexpected stat type %T","messagePattern":"unexpected stat type %T","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"util/layercopy/dest_linux.go","lineNumber":490,"sourceCode":"\nfunc (d *destination) flush() error {\n\treturn nil\n}\n\nfunc (d *destination) usage() (snapshots.Usage, error) {\n\tseen := map[inode]struct{}{}\n\tvar usage snapshots.Usage\n\terr := filepath.WalkDir(d.writeRoot, func(path string, ent fs.DirEntry, err error) error {\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tinfo, err := ent.Info()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tst, ok := info.Sys().(*syscall.Stat_t)\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unexpected stat type %T\", info.Sys())\n\t\t}\n\t\tino := statInode(st)\n\t\tif _, ok := seen[ino]; ok {\n\t\t\treturn nil\n\t\t}\n\t\tseen[ino] = struct{}{}\n\t\tif _, ok := d.crossLinks[ino]; ok {\n\t\t\treturn nil\n\t\t}\n\t\tusage.Inodes++\n\t\tusage.Size += st.Blocks * 512\n\t\treturn nil\n\t})\n\treturn usage, err\n}\n\nfunc copyMetadata(dstPath, srcPath string, srcInfo os.FileInfo, chown *Ownership, modeOverride *os.FileMode, userxattr bool, xattrErrorHandler XAttrErrorHandler, disableXAttrs bool) error {\n\tif srcInfo != nil {","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/dagger/dagger/blob/82ba2681dbe30d3547a1dc50ea495900ab5b6047/util/layercopy/dest_linux.go#L472-L508","documentation":"During usage() accounting, the write root is walked and each entry's os.FileInfo is asserted to carry a *syscall.Stat_t via info.Sys(). This holds on real Linux filesystems, but if the FileInfo's underlying system type is anything else the walk aborts with \"unexpected stat type %T\" (dest_linux.go:490). It is an internal invariant check protecting the inode-deduplication logic (statInode(st)).","triggerScenarios":"Calling Copier.Usage() when the write root is served by a filesystem/layer whose DirEntry.Info() does not return *syscall.Stat_t — e.g. mock/fake FileInfo in tests, FUSE or network filesystems with wrapped FileInfo implementations, or go1.12+ os.FileInfo wrappers.","commonSituations":"Unit tests injecting stub FileInfo without Sys() populated; exotic FUSE mounts (s3fs, gocryptfs wrappers) as the upperdir; libraries that wrap os.FileInfo and lose the Sys payload.","solutions":["Ensure the write root is on a regular Linux filesystem where Sys() returns *syscall.Stat_t.","In tests, use FileInfo implementations whose Sys() returns a real &syscall.Stat_t{}.","Avoid FileInfo-wrapping middleware between the walk and the copier; pass through the raw os FileInfo.","If a special filesystem must be measured, copy/measure from a bind-mounted real directory instead."],"exampleFix":"// before\ntype fakeInfo struct{ name string }\nfunc (f fakeInfo) Sys() any { return nil } // breaks Usage()\n// after\nfunc (f fakeInfo) Sys() any { return &syscall.Stat_t{Ino: 1, Blocks: 2} }","handlingStrategy":"validation","validationCode":"if info, err := filepathWalkProbe(writeRoot); err == nil {\n    if _, ok := info.Sys().(*syscall.Stat_t); !ok {\n        return fmt.Errorf(\"write root %s does not provide native stat; Usage unavailable\", writeRoot)\n    }\n}","typeGuard":"func hasNativeStat(info os.FileInfo) bool {\n    _, ok := info.Sys().(*syscall.Stat_t)\n    return ok\n}","tryCatchPattern":"usage, err := cop.Usage()\nif err != nil && strings.Contains(err.Error(), \"unexpected stat type\") {\n    // fall back to a plain du-style estimate or skip usage accounting\n}","preventionTips":["Keep the write root on regular Linux filesystems (ext4/xfs/tmpfs)","Make test FileInfo fakes return *syscall.Stat_t from Sys()","Probe Sys() once at startup if exotic mounts are possible"],"tags":["filesystem","syscall","invariant","usage"],"backgroundTag":"unexpected-stat-type","analyzedSha":"82ba2681dbe30d3547a1dc50ea495900ab5b6047","analyzedAt":"2026-09-05T07:21:37.930Z","contentChangedAt":"2026-09-05T07:21:37.930Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}