dagger/dagger · error
unexpected stat type %T
Error message
unexpected stat type %T
What it means
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)).
Source
Thrown at util/layercopy/dest_linux.go:490
func (d *destination) flush() error {
return nil
}
func (d *destination) usage() (snapshots.Usage, error) {
seen := map[inode]struct{}{}
var usage snapshots.Usage
err := filepath.WalkDir(d.writeRoot, func(path string, ent fs.DirEntry, err error) error {
if err != nil {
return err
}
info, err := ent.Info()
if err != nil {
return err
}
st, ok := info.Sys().(*syscall.Stat_t)
if !ok {
return fmt.Errorf("unexpected stat type %T", info.Sys())
}
ino := statInode(st)
if _, ok := seen[ino]; ok {
return nil
}
seen[ino] = struct{}{}
if _, ok := d.crossLinks[ino]; ok {
return nil
}
usage.Inodes++
usage.Size += st.Blocks * 512
return nil
})
return usage, err
}
func copyMetadata(dstPath, srcPath string, srcInfo os.FileInfo, chown *Ownership, modeOverride *os.FileMode, userxattr bool, xattrErrorHandler XAttrErrorHandler, disableXAttrs bool) error {
if srcInfo != nil {View on GitHub (pinned to 82ba2681db)
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.
Example fix
// before
type fakeInfo struct{ name string }
func (f fakeInfo) Sys() any { return nil } // breaks Usage()
// after
func (f fakeInfo) Sys() any { return &syscall.Stat_t{Ino: 1, Blocks: 2} } Defensive patterns
Strategy: validation
Validate before calling
if info, err := filepathWalkProbe(writeRoot); err == nil {
if _, ok := info.Sys().(*syscall.Stat_t); !ok {
return fmt.Errorf("write root %s does not provide native stat; Usage unavailable", writeRoot)
}
} Type guard
func hasNativeStat(info os.FileInfo) bool {
_, ok := info.Sys().(*syscall.Stat_t)
return ok
} Try / catch
usage, err := cop.Usage()
if err != nil && strings.Contains(err.Error(), "unexpected stat type") {
// fall back to a plain du-style estimate or skip usage accounting
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- mount before to ./a/: %w
- mount after to ./b/: %w
- failed to call utimes: %w
- failed to get stat_t for %T
- failed call to UtimesNanoAt
AI-assisted analysis of dagger/dagger@82ba2681db (2026-09-05).
Data as JSON: /api/errors/efe96d42aa51a22f.
Report an issue: GitHub.