AlistGo/alist · error

cannot copy parent dir to child

Error message

cannot copy parent dir to child

What it means

Copy() rejects copying a directory into its own subtree: strings.HasPrefix(dstDir.GetPath(), srcObj.GetPath()) detects that the destination is inside the source, which would recursively nest the copy inside itself. The guard mirrors the one in Move(). drivers/github/driver.go:529.

Source

Thrown at drivers/github/driver.go:529

		ObjName:    srcObj.GetName(),
		ObjPath:    srcObj.GetPath(),
		ParentName: stdpath.Base(parentDir),
		ParentPath: parentDir,
		TargetName: newName,
		TargetPath: stdpath.Join(parentDir, newName),
	}, "rename")
	if err != nil {
		return err
	}
	return d.commit(message, rootSha)
}

func (d *Github) Copy(ctx context.Context, srcObj, dstDir model.Obj) error {
	if !d.isOnBranch {
		return errors.New("cannot write to non-branch reference")
	}
	if strings.HasPrefix(dstDir.GetPath(), srcObj.GetPath()) {
		return errors.New("cannot copy parent dir to child")
	}
	d.commitMutex.Lock()
	defer d.commitMutex.Unlock()

	dstSha, newSha, _, _, err := d.copyWithoutRenewTree(srcObj, dstDir)
	if err != nil {
		return err
	}
	rootSha, err := d.renewParentTrees(dstDir.GetPath(), dstSha, newSha, "/")
	if err != nil {
		return err
	}
	message, err := getMessage(d.copyMsgTmpl, &MessageTemplateVars{
		UserName:   getUsername(ctx),
		ObjName:    srcObj.GetName(),
		ObjPath:    srcObj.GetPath(),
		ParentName: stdpath.Base(stdpath.Dir(srcObj.GetPath())),
		ParentPath: stdpath.Dir(srcObj.GetPath()),

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Choose a destination outside the source subtree (e.g. /a -> /backup/a).
  2. Fix caller logic to reject destinations prefixed by the source path.
  3. If duplicating in place was intended, copy to a sibling path first, then move.

Example fix

// before
Copy(src=/docs, dst=/docs/copy) // rejected

// after
Copy(src=/docs, dst=/backup/docs) // valid
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasPrefix(dstDir.GetPath()+"/", srcObj.GetPath()+"/") {
    return errors.New("cannot copy a directory into itself")
}

Type guard

func isCopyIntoSelf(src, dst model.Obj) bool {
    return strings.HasPrefix(stdpath.Clean(dst.GetPath())+"/", stdpath.Clean(src.GetPath())+"/")
}

Prevention

When it happens

Trigger: Copying /a to /a/b (destination path starts with the source path) through the UI or driver API.

Common situations: Drag-and-drop of a folder into its own child; automation computing dst as src + suffix without realizing the collision.

Related errors


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