{"record":{"id":"716bf46750011ccb","repo":"juicedata/juicefs","slug":"scan-trash-files","errorCode":null,"errorMessage":"scan trash files","messagePattern":"scan trash files","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/meta/base.go","lineNumber":3246,"sourceCode":"\nfunc (m *baseMeta) scanTrashFiles(ctx Context, scan trashFileScan) error {\n\tvar st syscall.Errno\n\tvar entries []*Entry\n\tif st = m.en.doReaddir(ctx, TrashInode, 1, &entries, -1); st != 0 {\n\t\treturn errors.Wrap(st, \"read trash\")\n\t}\n\tvar subEntries []*Entry\n\tfor _, entry := range entries {\n\t\tts, err := time.Parse(\"2006-01-02-15\", string(entry.Name))\n\t\tif err != nil {\n\t\t\tlogger.Warnf(\"bad entry as a subTrash: %s\", entry.Name)\n\t\t\tcontinue\n\t\t}\n\t\tif m.getFormat().DirStats {\n\t\t\tds, st := m.GetDirStat(ctx, entry.Inode)\n\t\t\tif st == 0 && ds != nil {\n\t\t\t\tif _, err := scan(entry.Inode, uint64(ds.length), ts, ds.inodes); err != nil {\n\t\t\t\t\treturn errors.Wrap(err, \"scan trash files\")\n\t\t\t\t}\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tlogger.Warnf(\"get dir stat %d: %s, fallback to readdir\", entry.Inode, st)\n\t\t}\n\t\tsubEntries = subEntries[:0]\n\t\tif st = m.en.doReaddir(ctx, entry.Inode, 1, &subEntries, -1); st != 0 {\n\t\t\tlogger.Warnf(\"readdir subEntry %d: %s\", entry.Inode, st)\n\t\t\tcontinue\n\t\t}\n\t\tfor _, se := range subEntries {\n\t\t\tif se.Attr.Typ == TypeFile {\n\t\t\t\tclean, err := scan(se.Inode, se.Attr.Length, ts, 1)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn errors.Wrap(err, \"scan trash files\")\n\t\t\t\t}\n\t\t\t\tif clean {\n\t\t\t\t\t// TODO: m.en.doUnlink(ctx, entry.Attr.Parent, string(entry.Name))","sourceCodeStart":3228,"sourceCodeEnd":3264,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/meta/base.go#L3228-L3264","documentation":"When scanning trash files, the per-entry scan callback returned an error; it is wrapped as 'scan trash files'. This propagates a failure from the caller-provided scan function (e.g. writing to a dump/backup target) during trash enumeration.","triggerScenarios":"Running juicefs dump/gc with trash scanning when the scan callback fails — typically the dump destination write fails, or the callback encounters an invalid entry it rejects.","commonSituations":"Dump target disk full or unwritable during 'juicefs dump'; S3/object store upload failure while backing up trash entries; interrupted pipes (juicefs dump | gzip where gzip dies).","solutions":["Inspect the wrapped inner error for the callback's actual failure (disk full, broken pipe, upload error)","Free space / fix permissions on the dump destination and retry","If piping, ensure downstream consumers stay alive: juicefs dump ... | gzip > file.gz","Re-run the dump — it is restartable since it reads metadata non-destructively"],"exampleFix":"// before\njuicefs dump meta.db dump.json   // scan trash files: write ...: no space left on device\n// after\ndf -h /backup && juicefs dump meta.db /backup/dump.json","handlingStrategy":"try-catch","validationCode":"// ensure dump destination is writable and has space before scanning\nif fi, err := os.Stat(destDir); err != nil || !fi.IsDir() {\n  // fix destination first\n}","typeGuard":null,"tryCatchPattern":"if err := scanTrashFiles(ctx, scan); err != nil {\n  // errors.As/wrap reveals the callback's real failure (ENOSPC, broken pipe, upload error)\n  return err\n}","preventionTips":["Check free space on the dump destination before long trash scans","Avoid piping dumps into fragile consumers; write to a file instead","Monitor object-store upload health when backing up to S3-compatible targets"],"tags":["metadata","trash","scan"],"backgroundTag":"callback-failed","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}