{"record":{"id":"a2289dd290c7d502","repo":"AlistGo/alist","slug":"not-a-folder","errorCode":null,"errorMessage":"not a folder","messagePattern":"not a folder","errorType":"exception","errorClass":"NotFolder","httpStatus":null,"severity":"error","filePath":"internal/errs/object.go","lineNumber":11,"sourceCode":"package errs\n\nimport (\n\t\"errors\"\n\n\tpkgerr \"github.com/pkg/errors\"\n)\n\nvar (\n\tObjectNotFound = errors.New(\"object not found\")\n\tNotFolder      = errors.New(\"not a folder\")\n\tNotFile        = errors.New(\"not a file\")\n)\n\nfunc IsObjectNotFound(err error) bool {\n\treturn errors.Is(pkgerr.Cause(err), ObjectNotFound)\n}\n","sourceCodeStart":1,"sourceCodeEnd":18,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/internal/errs/object.go#L1-L18","documentation":"NotFolder is a sentinel in internal/errs/object.go stating the resolved object exists but is not a directory. Operations that require a directory target (listing it, mkdir inside it, moving something into it) return it when the path names a file.","triggerScenarios":"Listing a path that is a regular file; creating a folder under a path that is actually a file (Mkdir); renaming/moving a file into a destination that is a file; upload with a directory component that resolves to an existing file.","commonSituations":"A file and intended folder share the same name (e.g. 'movie' file vs 'movie/' directory); case-insensitive storages masking a name collision; stale cache saying a path is a folder after it was replaced by a file; FTP clients issuing CWD against a file.","solutions":["Check the object type at that path and use the correct target (the actual folder)","Rename or delete the conflicting file that occupies the folder name","Invalidate the cached meta for that path if the remote was changed externally","Add a pre-check on model.Obj.IsDir() before directory-requiring calls"],"exampleFix":"// before\nerr := fs.Mkdir(ctx, \"/data/file.txt/newdir\")\n\n// after\nobj, err := op.Get(ctx, \"/data/file.txt\")\nif err == nil && !obj.IsDir() {\n    return errs.NotFolder\n}","handlingStrategy":"type-guard","validationCode":"// check the target is a directory before directory-requiring ops\nif obj, err := op.Get(ctx, dst); err == nil && !obj.IsDir() {\n    return errs.NotFolder\n}","typeGuard":"func requiresFolder(obj model.Obj) error {\n    if !obj.IsDir() { return errs.NotFolder }\n    return nil\n}","tryCatchPattern":"if err := fs.MakeDir(ctx, path); err != nil {\n    if errors.Is(errors.Cause(err), errs.NotFolder) {\n        // a file occupies the folder name — surface a clear message\n    }\n}","preventionTips":["Pre-check IsDir() on destinations","Avoid file/folder name collisions at the same path","Refresh cache after replacing a folder with a file","Validate FTP CWD targets client-side"],"tags":["filesystem","validation","type-mismatch"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}