AlistGo/alist · error

same-name files cannot be moved

Error message

same-name files cannot be moved

What it means

Returned by Alias.Move when getReqPath for the source object fails with errs.NotImplement: with ProtectSameName enabled, the source path exists in multiple underlying destinations sharing one alias key, so the driver cannot determine which physical file to move.

Source

Thrown at drivers/alias/driver.go:150

		return errs.PermissionDenied
	}
	reqPath, err := d.getReqPath(ctx, parentDir, true)
	if err == nil {
		return fs.MakeDir(ctx, stdpath.Join(*reqPath, dirName))
	}
	if errs.IsNotImplement(err) {
		return errors.New("same-name dirs cannot make sub-dir")
	}
	return err
}

func (d *Alias) Move(ctx context.Context, srcObj, dstDir model.Obj) error {
	if !d.Writable {
		return errs.PermissionDenied
	}
	srcPath, err := d.getReqPath(ctx, srcObj, false)
	if errs.IsNotImplement(err) {
		return errors.New("same-name files cannot be moved")
	}
	if err != nil {
		return err
	}
	dstPath, err := d.getReqPath(ctx, dstDir, true)
	if errs.IsNotImplement(err) {
		return errors.New("same-name dirs cannot be moved to")
	}
	if err != nil {
		return err
	}
	return fs.Move(ctx, *srcPath, *dstPath)
}

func (d *Alias) Rename(ctx context.Context, srcObj model.Obj, newName string) error {
	if !d.Writable {
		return errs.PermissionDenied
	}

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Use unique alias keys per destination instead of one key over many paths
  2. Move the file via the underlying storage mount directly
  3. Disable ProtectSameName if writing to the first matching backend is acceptable
  4. Delete the duplicate copy in one destination so the source resolves uniquely

Example fix

// before — ambiguous through alias
fs.Move(ctx, "/alias/data/file.txt", "/alias/target")

// after — address the concrete backend
fs.Move(ctx, "/netdisk_a/docs/file.txt", "/netdisk_a/target")
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the source path resolves in exactly one destination before moving
if len(d.pathMap[rootOf(srcPath)]) > 1 && d.ProtectSameName {
    return errors.New("source is mirrored across destinations; move via a concrete mount")
}

Type guard

// Go
func isSameNameErr(err error) bool {
    return err != nil && strings.Contains(err.Error(), "same-name")
}

Try / catch

if err := d.Move(ctx, src, dst); isSameNameErr(err) {
    // retry against each concrete backend explicitly
} else if err != nil { return err }

Prevention

When it happens

Trigger: ProtectSameName=true, the same alias key mapped to 2+ destinations, the source file present in more than one of them, and a Move(srcObj, dstDir) call through the alias mount.

Common situations: Merged mirror mounts (same content mirrored to two storages) with protect-mode on; users try to reorganize files via the alias entry and hit the ambiguity guard on the file being moved.

Related errors


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