{"record":{"id":"d1ae1fb1c1148faa","repo":"juicedata/juicefs","slug":"only-root-can-restore-files-from-trash","errorCode":null,"errorMessage":"only root can restore files from trash","messagePattern":"only root can restore files from trash","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/restore.go","lineNumber":50,"sourceCode":"\t\t\t\tName:  \"put-back\",\n\t\t\t\tUsage: \"move the recovered files into original directory\",\n\t\t\t},\n\t\t\t&cli.IntFlag{\n\t\t\t\tName:  \"threads\",\n\t\t\t\tValue: 10,\n\t\t\t\tUsage: \"number of threads\",\n\t\t\t},\n\t\t},\n\t}\n}\n\nfunc restore(ctx *cli.Context) error {\n\tsetup0(ctx, 2, 0)\n\tif runtime.GOOS == \"windows\" && !utils.IsWinAdminOrElevatedPrivilege() {\n\t\treturn fmt.Errorf(\"restore command requires Administrator or elevated privilege on Windows\")\n\t}\n\tif os.Getuid() != 0 && runtime.GOOS != \"windows\" {\n\t\treturn fmt.Errorf(\"only root can restore files from trash\")\n\t}\n\tremovePassword(ctx.Args().Get(0))\n\tm := meta.NewClient(ctx.Args().Get(0), nil)\n\t_, err := m.Load(true)\n\tif err != nil {\n\t\treturn err\n\t}\n\tfor i := 1; i < ctx.NArg(); i++ {\n\t\thour := ctx.Args().Get(i)\n\t\tdoRestore(m, hour, ctx.Bool(\"put-back\"), ctx.Int(\"threads\"))\n\t}\n\treturn nil\n}\n\nfunc doRestore(m meta.Meta, hour string, putBack bool, threads int) {\n\tif err := m.NewSession(false); err != nil {\n\t\tlogger.Warningf(\"running without sessions because fail to new session: %s\", err)\n\t} else {","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/cmd/restore.go#L32-L68","documentation":"Restoring files from JuiceFS trash manipulates metadata owned by the volume and is restricted to root on POSIX systems. After the Windows-specific elevation check, restore verifies os.Getuid() == 0 and returns this error when a non-root user runs it on Linux/macOS. Note the check is skipped on Windows, where the elevation check above applies instead.","triggerScenarios":"Running `juicefs restore <meta-url> <inode|name>` as a non-root user on Linux or macOS; the condition os.Getuid() != 0 && runtime.GOOS != \"windows\" evaluates true.","commonSituations":"Running restore via sudo-less automation or a service account; container environments where the entrypoint user is non-root; operators accustomed to other JuiceFS commands (like info) that do not require root.","solutions":["Re-run the command with sudo: sudo juicefs restore <meta-url> ...","If in a container, start it as root (--user 0 / run as root entrypoint).","Delegate the restore to an administrator who has root on the client machine.","On Windows clients, use the Windows-elevated path instead (Administrator privilege check)."],"exampleFix":"// before\njuicefs restore sqlite3:///etc/juicefs/test.db 100\n// after\nsudo juicefs restore sqlite3:///etc/juicefs/test.db 100","handlingStrategy":"validation","validationCode":"# shell pre-check before invoking restore\n[ \"$(id -u)\" -eq 0 ] || { echo \"restore must run as root\"; exit 1; }","typeGuard":null,"tryCatchPattern":"cmd := exec.Command(\"juicefs\", \"restore\", metaURL, target)\nif err := cmd.Run(); err != nil && strings.Contains(err.Error(), \"only root can restore\") {\n    // retry under sudo: exec.Command(\"sudo\", \"juicefs\", \"restore\", ...)\n}","preventionTips":["Run trash restore operations via sudo or as the root user by default.","Ensure containers executing restore run as uid 0.","Document which JuiceFS commands require root (restore, gc-like maintenance) in team runbooks.","Add a uid check in automation scripts before calling restore to fail fast with a clear message."],"tags":["root","permission","trash","cli","linux"],"backgroundTag":"permission-denied","analyzedSha":"c9a67b23e8e08ec23ec331aa6f1675e2319e921c","analyzedAt":"2026-09-06T17:55:48.476Z","contentChangedAt":"2026-09-06T17:55:48.476Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}