AlistGo/alist · warning

cannot move a submodule

Error message

cannot move a submodule

What it means

During Move()'s handling of the /aa/bb/1 -> /aa/ case, the driver scans the source parent tree for the entry to move and finds its type is 'commit' — a git submodule pointer. Submodules cannot be relocated via the tree API because the pointer references another repository, so the move is rejected. drivers/github/driver.go:310.

Source

Thrown at drivers/github/driver.go:310

		ancestorNewSha, err := d.newTree(ancestorOldSha, []interface{}{*delSrc, *dstNextTree})
		if err != nil {
			return err
		}
		rootSha, err = d.renewParentTrees(srcParentPath, ancestorOldSha, ancestorNewSha, "/")
		if err != nil {
			return err
		}
	} else if strings.HasPrefix(srcObj.GetPath(), dstDir.GetPath()) { // /aa/bb/1 -> /aa/
		srcParentPath := stdpath.Dir(srcObj.GetPath())
		srcParentTree, srcParentOldSha, err := d.getTreeDirectly(srcParentPath)
		if err != nil {
			return err
		}
		var src *TreeObjReq = nil
		for _, t := range srcParentTree.Trees {
			if t.Path == srcObj.GetName() {
				if t.Type == "commit" {
					return errors.New("cannot move a submodule")
				}
				src = &t.TreeObjReq
				break
			}
		}
		if src == nil {
			return errs.ObjectNotFound
		}

		delSrc := *src
		delSrc.Sha = nil
		delSrcTree := make([]interface{}, 0, 2)
		delSrcTree = append(delSrcTree, delSrc)
		if len(srcParentTree.Trees) == 1 {
			delSrcTree = append(delSrcTree, map[string]string{
				"path":    ".gitkeep",
				"mode":    "100644",
				"type":    "blob",

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Perform the reorganization with git (edit .gitmodules, git mv) and push, rather than through the driver.
  2. Leave submodule entries untouched in the mounted view.
  3. Hide submodule entries from listings if they cause confusion.
Defensive patterns

Strategy: type-guard

Validate before calling

// check tree entry type before moving
for _, t := range srcParentTree.Trees {
    if t.Path == srcObj.GetName() && t.Type == "commit" {
        return errors.New("submodule entries cannot be moved via the tree API")
    }
}

Type guard

func isCommitEntry(t TreeObj) bool { return t.Type == "commit" }

Try / catch

if err := d.Move(ctx, src, dst); err != nil && strings.Contains(err.Error(), "submodule") {
    // fall back to git-side reorganization
}

Prevention

When it happens

Trigger: Moving an object upward out of its parent where the located tree entry has Type == "commit" (submodule).

Common situations: Repos with vendored submodules where a user tries to reorganize directories through the file browser; submodule entries surfacing in listings and being treated like normal folders.

Related errors


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