AlistGo/alist · error

file exists

Error message

file exists

What it means

MakeDir checks whether the path to create already exists; if an existing object at that path is a file (not a directory), creating the directory cannot proceed and it returns 'file exists'. This happens after the stat succeeded, so the conflict is a real filesystem object, not a race with a missing path.

Source

Thrown at internal/op/fs.go:359

					}
				case driver.Mkdir:
					err = s.MakeDir(ctx, parentDir, dirName)
					if err == nil && !utils.IsBool(lazyCache...) {
						ClearCache(storage, parentPath)
					}
				default:
					return nil, errs.NotImplement
				}
				return nil, errors.WithStack(err)
			}
			return nil, errors.WithMessage(err, "failed to check if dir exists")
		}
		// dir exists
		if f.IsDir() {
			return nil, nil
		}
		// dir to make is a file
		return nil, errors.New("file exists")
	})
	return err
}

func Move(ctx context.Context, storage driver.Driver, srcPath, dstDirPath string, lazyCache ...bool) error {
	if storage.Config().CheckStatus && storage.GetStorage().Status != WORK {
		return errors.Errorf("storage not init: %s", storage.GetStorage().Status)
	}
	srcPath = utils.FixAndCleanPath(srcPath)
	dstDirPath = utils.FixAndCleanPath(dstDirPath)
	srcRawObj, err := Get(ctx, storage, srcPath)
	if err != nil {
		return errors.WithMessage(err, "failed to get src object")
	}
	srcObj := model.UnwrapObj(srcRawObj)
	dstDir, err := GetUnwrap(ctx, storage, dstDirPath)
	if err != nil {
		return errors.WithMessage(err, "failed to get dst dir")

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Delete or rename the existing file that occupies the path, then retry
  2. Adjust the destination path to avoid the collision (e.g. prefix or different folder name)
  3. If it came from an upload flow, fix the flow to not create files with the same name as intended directories

Example fix

// before
err := op.MakeDir(ctx, storage, "/data/report.txt/parts")
// after: remove the conflicting file first
if obj, _ := op.GetUnwrap(ctx, storage, "/data/report.txt"); obj != nil && !obj.IsDir() {
    _ = op.Remove(ctx, storage, "/data/report.txt")
}
err := op.MakeDir(ctx, storage, "/data/report.txt/parts")
Defensive patterns

Strategy: validation

Validate before calling

// Before MakeDir: ensure no file shadows any prefix of the path
p := dstPath
for p != "/" && p != "." {
    if obj, err := op.GetUnwrap(ctx, storage, p); err == nil && obj != nil && !obj.IsDir() {
        return fmt.Errorf("file %s blocks directory creation", p)
    }
    p = stdpath.Dir(p)
}

Type guard

func pathIsClearOfFiles(ctx context.Context, s driver.Driver, path string) bool {
    obj, err := op.GetUnwrap(ctx, s, path)
    return err != nil || obj == nil || obj.IsDir()
}

Try / catch

if err := op.MakeDir(ctx, storage, dir); err != nil {
    if strings.Contains(err.Error(), "file exists") {
        // resolve the collision: rename or remove the blocking file
    }
}

Prevention

When it happens

Trigger: Calling op.MakeDir on a path whose parent-most conflicting segment is a regular file — e.g. MakeDir('/a/b') where '/a' is a file. Also uploading with auto-mkdir into a path shadowed by an earlier uploaded file of the same name.

Common situations: A previous upload created a file where a directory is now expected (common with generated paths like /books/2024 where 'books' was uploaded as a file); WebDAV clients that mkdir after put; copy/move targets colliding with existing files.

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/e4dd745a453ad48d. Report an issue: GitHub.