{"record":{"id":"cb33fe8d1a58ca95","repo":"juicedata/juicefs","slug":"s-is-non-empty-directory","errorCode":null,"errorMessage":"%s is non-empty directory","messagePattern":"(.+?) is non-empty directory","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/object/webdav.go","lineNumber":102,"sourceCode":"\nfunc (w *webdav) Delete(ctx context.Context, key string, getters ...AttrGetter) error {\n\tinfo, err := w.c.Stat(key)\n\tif gowebdav.IsErrNotFound(err) {\n\t\treturn nil\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n\tif info.IsDir() {\n\t\tinfos, err := w.c.ReadDir(key)\n\t\tif err != nil {\n\t\t\tif gowebdav.IsErrNotFound(err) {\n\t\t\t\treturn nil\n\t\t\t}\n\t\t\treturn err\n\t\t}\n\t\tif len(infos) != 0 {\n\t\t\treturn fmt.Errorf(\"%s is non-empty directory\", key)\n\t\t}\n\t}\n\treturn w.c.Remove(key)\n}\n\nfunc (w *webdav) Copy(ctx context.Context, dst, src string) error {\n\treturn w.c.Copy(src, dst, true)\n}\n\ntype webDAVFile struct {\n\tos.FileInfo\n\tname string\n}\n\nfunc (w webDAVFile) Name() string {\n\treturn w.name\n}\n","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/juicedata/juicefs/blob/c9a67b23e8e08ec23ec331aa6f1675e2319e921c/pkg/object/webdav.go#L84-L120","documentation":"webdav.Delete refuses to remove a collection (directory) that still contains entries. It PROPFINDs the target; if not found it's already gone, but if entries exist it returns \"<key> is non-empty directory\" instead of recursing.","triggerScenarios":"Deleting a WebDAV directory path that has children; also hit during garbage collection or cleanup operations that walk keys resembling directories.","commonSituations":"Deleting a 'folder-like' object left by another client; mount point cleanup where empty-dir detection disagrees (server returns implicit entries); keys ending in '/' that other clients populated.","solutions":["Empty the directory first (delete children), then delete the directory","Use a recursive delete at the application level before calling Delete","Check the server's PROPFIND result — some servers return phantom entries; verify real children exist","If the directory is actually empty, the listing may be stale — retry"],"exampleFix":"// before\nstore.Delete(ctx, \"photos/\")\n// after\nobjs, _ := store.List(ctx, \"photos/\", \"\", -1, true)\nfor _, o := range objs { store.Delete(ctx, o.Key()) }\nstore.Delete(ctx, \"photos/\")","handlingStrategy":"fallback","validationCode":"func dirEmpty(ctx context.Context, w object.ObjectStorage, key string) (bool, error) {\n\tobjs, _, err := w.List(ctx, key, \"\", 1, true)\n\tif err != nil { return false, err }\n\treturn len(objs) == 0, nil\n}","typeGuard":null,"tryCatchPattern":"err := store.Delete(ctx, key)\nif err != nil && strings.HasSuffix(err.Error(), \"is non-empty directory\") {\n\t// list children, delete each, then delete the directory\n}","preventionTips":["Delete children before deleting a directory key","Treat keys ending in '/' as collections and recurse","Verify the bucket/volume really contains the expected children"],"tags":["webdav","delete","directory","object-storage"],"backgroundTag":"directory-not-found","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"}