gastownhall/beads · error

walk returned no file information for %s

Error message

walk returned no file information for %s

What it means

MeasureDirectorySize walks a directory tree summing file sizes via filepath.Walk. The walk callback guards against a nil os.FileInfo, which the walk contract should never produce when no walkErr is set. This error means the walker received a nil info for a path without an accompanying error — an unexpected internal/filesystem inconsistency, so it is surfaced instead of silently counting the entry as zero bytes.

Source

Thrown at internal/storage/directory_size.go:51

	}

	return measureDirectorySizeWithWalk(ctx, resolvedRoot, filepath.Walk)
}

func measureDirectorySizeWithWalk(ctx context.Context, root string, walk directoryWalkFunc) (int64, error) {
	var size int64
	err := walk(root, func(path string, info os.FileInfo, walkErr error) error {
		if err := ctx.Err(); err != nil {
			return err
		}
		if walkErr != nil {
			if path != root && errors.Is(walkErr, fs.ErrNotExist) {
				return nil
			}
			return walkErr
		}
		if info == nil {
			return fmt.Errorf("walk returned no file information for %s", path)
		}
		if info.IsDir() {
			return nil
		}
		if info.Size() < 0 || info.Size() > math.MaxInt64-size {
			return fmt.Errorf("directory size overflows int64 at %s", path)
		}
		size += info.Size()
		return nil
	})
	if err != nil {
		return 0, err
	}
	return size, nil
}

View on GitHub (pinned to 71377f2769)

Solutions

  1. Inspect the custom walk function passed to measureDirectorySizeWithWalk; ensure it never invokes the callback with a nil FileInfo and nil error.
  2. Stat the reported path manually (os.Stat/os.Lstat) to check whether the filesystem is returning valid metadata for that entry.
  3. If a network/FUSE/overlay filesystem is involved, retry the measurement or check the mount health, since metadata can transiently fail to resolve.
  4. If the path is genuinely gone mid-walk, re-run MeasureDirectorySize; the normal race path (walkErr=fs.ErrNotExist) is tolerated, so only broken metadata triggers this.

Example fix

// before: custom walk calls cb(path, nil, nil) for skipped entries
cb(path, nil, nil)
// after: skip the callback entirely or pass an error
cb(path, nil, fs.ErrNotExist) // tolerated by the size walker for non-root paths
Defensive patterns

Strategy: type-guard

Validate before calling

if info, err := os.Stat(root); err != nil || !info.IsDir() {
    return fmt.Errorf("root %s is not a statable directory: %w", root, err)
}

Type guard

func validWalkEntry(path string, info os.FileInfo, err error) bool {
    return err == nil && info != nil
}

Try / catch

size, err := storage.MeasureDirectorySize(ctx, root)
if err != nil {
    if strings.Contains(err.Error(), "walk returned no file information") {
        // invariant violation: re-run once or log and fall back to du-style estimate
    }
    return err
}

Prevention

When it happens

Trigger: During MeasureDirectorySize, filepath.Walk invokes the callback with path having a nil os.FileInfo and a nil walkErr — a state outside the documented Walk contract, typically only reachable with a custom walk function injected via measureDirectorySizeWithWalk or exotic filesystem behavior.

Common situations: Custom/dummy walk implementations passed in tests that call the callback with (path, nil, nil); filesystem layers (FUSE, network mounts) that misreport FileInfo; regressions in the walk function itself.

Related errors


AI-assisted analysis of gastownhall/beads@71377f2769 (2026-08-30). Data as JSON: /api/errors/70a8f9aa5ca8b0f1. Report an issue: GitHub.