{"record":{"id":"48a0d811bccee67e","repo":"AlistGo/alist","slug":"delete-root-folder-is-not-allowed-please-goto-the","errorCode":null,"errorMessage":"delete root folder is not allowed, please goto the manage page to delete the storage instead","messagePattern":"delete root folder is not allowed, please goto the manage page to delete the storage instead","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/op/fs.go","lineNumber":484,"sourceCode":"\t\t\t}\n\t\t}\n\tcase driver.Copy:\n\t\terr = s.Copy(ctx, srcObj, dstDir)\n\t\tif err == nil && !utils.IsBool(lazyCache...) {\n\t\t\tClearCache(storage, dstDirPath)\n\t\t}\n\tdefault:\n\t\treturn errs.NotImplement\n\t}\n\treturn errors.WithStack(err)\n}\n\nfunc Remove(ctx context.Context, storage driver.Driver, path string) error {\n\tif storage.Config().CheckStatus && storage.GetStorage().Status != WORK {\n\t\treturn errors.Errorf(\"storage not init: %s\", storage.GetStorage().Status)\n\t}\n\tif utils.PathEqual(path, \"/\") {\n\t\treturn errors.New(\"delete root folder is not allowed, please goto the manage page to delete the storage instead\")\n\t}\n\tpath = utils.FixAndCleanPath(path)\n\trawObj, err := Get(ctx, storage, path)\n\tif err != nil {\n\t\t// if object not found, it's ok\n\t\tif errs.IsObjectNotFound(err) {\n\t\t\tlog.Debugf(\"%s have been removed\", path)\n\t\t\treturn nil\n\t\t}\n\t\treturn errors.WithMessage(err, \"failed to get object\")\n\t}\n\tdirPath := stdpath.Dir(path)\n\n\tswitch s := storage.(type) {\n\tcase driver.Remove:\n\t\terr = s.Remove(ctx, model.UnwrapObj(rawObj))\n\t\tif err == nil {\n\t\t\tdelCacheObj(storage, dirPath, rawObj)","sourceCodeStart":466,"sourceCodeEnd":502,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/op/fs.go#L466-L502","documentation":"op.Remove refuses to delete the storage root path '/' because that operation would be interpreted by the driver as wiping the whole storage, not an emptying of a folder. The guard sits before any driver call, so it fires even for storages that would otherwise allow it. Users must delete the storage itself from the admin page instead.","triggerScenarios":"Any delete request (API, WebDAV DELETE, or copy/move cleanup) whose normalized path equals '/' on a mounted storage.","commonSituations":"WebDAV clients issuing recursive delete on the mount root; scripts globbing to '/'; users trying to 'empty' a storage by deleting its root.","solutions":["Delete specific subpaths instead of the root","To remove everything, delete and recreate the storage on the manage page","Guard scripts/WebDAV clients from issuing DELETE on '/'"],"exampleFix":"// before\nerr := op.Remove(ctx, storage, \"/\")\n// after\ndir := \"/some/subdir\"\nerr := op.Remove(ctx, storage, dir)","handlingStrategy":"validation","validationCode":"// Before any delete\nif utils.PathEqual(path, \"/\") {\n    return errors.New(\"refusing to delete storage root\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reject root-path DELETEs in API/WebDAV adapters at the boundary","Test cleanup scripts against '/' deliberately","Use the manage page to remove whole storages"],"tags":["filesystem","delete","root-path","safety-guard"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}