containerd/containerd · error
stat %s: %w
Error message
stat %s: %w
What it means
wrapUserFile wraps a user-supplied fs.File (e.g. a user-supplied passwd/group file source) and first stats it; if Stat fails the file is closed and this error wraps the stat failure with the file name. The library cannot determine the file's size/mode, so it refuses to read it. It prevents later mis-parsing of unusable file sources.
Source
Thrown at pkg/oci/spec_opts.go:1876
if err != nil {
return nil, err
}
return wrapUserFile(f, name)
}
// maxUserFileBytes caps how much data is read from any user-database file
// opened via openUserFile. Real systems keep these files well under 1 MiB;
// 10 MiB is generous headroom while keeping peak memory during
// user.ParsePasswd/ParseGroup bounded to single-digit MiB.
const maxUserFileBytes = 10 << 20
// wrapUserFile rejects non-regular sources and returns an fs.File that
// errors out if more than maxUserFileBytes are read from it.
func wrapUserFile(f fs.File, name string) (fs.File, error) {
info, err := f.Stat()
if err != nil {
f.Close()
return nil, fmt.Errorf("stat %s: %w", name, err)
}
if !info.Mode().IsRegular() {
f.Close()
return nil, fmt.Errorf("%s is not a regular file", name)
}
return &limitedFile{
File: f,
// Allow one byte past the cap so an overflow surfaces as an
// error rather than a silent EOF that the parser would treat as
// a clean end-of-file (and miss any entries past the cap).
r: &io.LimitedReader{R: f, N: maxUserFileBytes + 1},
name: name,
}, nil
}
// limitedFile is an fs.File whose Read returns an error once more than
// maxUserFileBytes have been read.
type limitedFile struct {View on GitHub (pinned to 4246446a2b)
Solutions
- Check the wrapped error to see why Stat failed and fix the underlying FS/permissions.
- Verify the file exists in the provided fs.FS before calling the spec option.
- Provide the file via a regular os file path if the custom FS is unreliable.
- Ensure the fs.File implementation returns valid Stat info for regular files.
Example fix
// before
f, err := customFS.Open("etc/passwd") // stat fails later
// after
if _, err := fs.Stat(customFS, "etc/passwd"); err != nil {
return fmt.Errorf("user file missing: %w", err)
} Defensive patterns
Strategy: validation
Validate before calling
if _, err := fs.Stat(userFS, "etc/passwd"); err != nil {
return fmt.Errorf("user source unavailable: %w", err)
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "stat ") {
// fall back to a plain os file source
}
} Prevention
- Ensure custom fs.FS implementations return working Stat
- Verify embedded files exist at build time
- Prefer os file paths for user sources in production
- Wrap custom FS errors with the file name for diagnosis
When it happens
Trigger: Passing a custom fs.FS / io/fs.File source to spec-opt parsers like WithCustomUser (or etc/passwd overrides) where calling Stat() on the opened file returns an error — e.g. the file was deleted, the custom FS errors, or permissions deny access.
Common situations: Custom embed.FS or memfs missing the entry; a network-backed FS returning stat errors; symlink loops or permission-denied paths in a custom resolver.
Related errors
- %s is not a regular file
- cannot load spec config file: %w
- unable to find group %s: %w
- unable to find group %s
- %q exceeds %d bytes
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/93b0eacc5b5e1fbe.
Report an issue: GitHub.