{"record":{"id":"93b0eacc5b5e1fbe","repo":"containerd/containerd","slug":"stat-s-w","errorCode":null,"errorMessage":"stat %s: %w","messagePattern":"stat (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/oci/spec_opts.go","lineNumber":1876,"sourceCode":"\tif err != nil {\n\t\treturn nil, err\n\t}\n\treturn wrapUserFile(f, name)\n}\n\n// maxUserFileBytes caps how much data is read from any user-database file\n// opened via openUserFile. Real systems keep these files well under 1 MiB;\n// 10 MiB is generous headroom while keeping peak memory during\n// user.ParsePasswd/ParseGroup bounded to single-digit MiB.\nconst maxUserFileBytes = 10 << 20\n\n// wrapUserFile rejects non-regular sources and returns an fs.File that\n// errors out if more than maxUserFileBytes are read from it.\nfunc wrapUserFile(f fs.File, name string) (fs.File, error) {\n\tinfo, err := f.Stat()\n\tif err != nil {\n\t\tf.Close()\n\t\treturn nil, fmt.Errorf(\"stat %s: %w\", name, err)\n\t}\n\tif !info.Mode().IsRegular() {\n\t\tf.Close()\n\t\treturn nil, fmt.Errorf(\"%s is not a regular file\", name)\n\t}\n\treturn &limitedFile{\n\t\tFile: f,\n\t\t// Allow one byte past the cap so an overflow surfaces as an\n\t\t// error rather than a silent EOF that the parser would treat as\n\t\t// a clean end-of-file (and miss any entries past the cap).\n\t\tr:    &io.LimitedReader{R: f, N: maxUserFileBytes + 1},\n\t\tname: name,\n\t}, nil\n}\n\n// limitedFile is an fs.File whose Read returns an error once more than\n// maxUserFileBytes have been read.\ntype limitedFile struct {","sourceCodeStart":1858,"sourceCodeEnd":1894,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/pkg/oci/spec_opts.go#L1858-L1894","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nf, err := customFS.Open(\"etc/passwd\") // stat fails later\n// after\nif _, err := fs.Stat(customFS, \"etc/passwd\"); err != nil {\n  return fmt.Errorf(\"user file missing: %w\", err)\n}","handlingStrategy":"validation","validationCode":"if _, err := fs.Stat(userFS, \"etc/passwd\"); err != nil {\n  return fmt.Errorf(\"user source unavailable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n  if strings.Contains(err.Error(), \"stat \") {\n    // fall back to a plain os file source\n  }\n}","preventionTips":["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"],"tags":["oci","filesystem","user-files","spec-opts"],"backgroundTag":"file-stat-failed","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}