AlistGo/alist · error

cannot move parent dir to child

Error message

cannot move parent dir to child

What it means

Move() rejects moving a directory into its own subtree: strings.HasPrefix(dstDir.GetPath(), srcObj.GetPath()) means the destination lives inside the source (e.g. moving /docs into /docs/sub). Such a move is either a no-op or would create a cycle in the git tree, so it is refused. drivers/github/driver.go:252.

Source

Thrown at drivers/github/driver.go:252

	commitMessage, err := getMessage(d.mkdirMsgTmpl, &MessageTemplateVars{
		UserName:   getUsername(ctx),
		ObjName:    dirName,
		ObjPath:    stdpath.Join(parentDir.GetPath(), dirName),
		ParentName: parentDir.GetName(),
		ParentPath: parentDir.GetPath(),
	}, "mkdir")
	if err != nil {
		return err
	}
	return d.commit(commitMessage, rootSha)
}

func (d *Github) Move(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 move parent dir to child")
	}
	d.commitMutex.Lock()
	defer d.commitMutex.Unlock()

	var rootSha string
	if strings.HasPrefix(dstDir.GetPath(), stdpath.Dir(srcObj.GetPath())) { // /aa/1 -> /aa/bb/
		dstOldSha, dstNewSha, ancestorOldSha, srcParentTree, err := d.copyWithoutRenewTree(srcObj, dstDir)
		if err != nil {
			return err
		}

		srcParentPath := stdpath.Dir(srcObj.GetPath())
		dstRest := dstDir.GetPath()[len(srcParentPath):]
		if dstRest[0] == '/' {
			dstRest = dstRest[1:]
		}
		dstNextName, _, _ := strings.Cut(dstRest, "/")
		dstNextPath := stdpath.Join(srcParentPath, dstNextName)

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Choose a destination outside the source directory's subtree (e.g. /a -> /b/a).
  2. If the intent was renaming, use Rename on the object instead of Move.
  3. Fix automation logic to reject dst paths with the src path as prefix.

Example fix

// before
Move(src=/docs, dst=/docs/archive) // rejected

// after
Move(src=/docs, dst=/archive/docs) // valid
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Prevention

When it happens

Trigger: Moving /a to /a/b, or /a to /a itself (path prefix collision), through the OpenList UI or API against the GitHub driver.

Common situations: User drags a folder into one of its own children by mistake; destination path typo'd to start with the source path; automation computing destination paths from source paths without excluding descendants.

Related errors


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