{"record":{"id":"a132209d64bb15ce","repo":"AlistGo/alist","slug":"cannot-move-in-place","errorCode":null,"errorMessage":"cannot move in place","messagePattern":"cannot move in place","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"drivers/github/driver.go","lineNumber":342,"sourceCode":"\t\tif len(srcParentTree.Trees) == 1 {\n\t\t\tdelSrcTree = append(delSrcTree, map[string]string{\n\t\t\t\t\"path\":    \".gitkeep\",\n\t\t\t\t\"mode\":    \"100644\",\n\t\t\t\t\"type\":    \"blob\",\n\t\t\t\t\"content\": \"\",\n\t\t\t})\n\t\t}\n\t\tsrcParentNewSha, err := d.newTree(srcParentOldSha, delSrcTree)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tsrcRest := srcObj.GetPath()[len(dstDir.GetPath()):]\n\t\tif srcRest[0] == '/' {\n\t\t\tsrcRest = srcRest[1:]\n\t\t}\n\t\tsrcNextName, _, ok := strings.Cut(srcRest, \"/\")\n\t\tif !ok { // /aa/1 -> /aa/\n\t\t\treturn errors.New(\"cannot move in place\")\n\t\t}\n\t\tsrcNextPath := stdpath.Join(dstDir.GetPath(), srcNextName)\n\t\tsrcNextTreeSha, err := d.renewParentTrees(srcParentPath, srcParentOldSha, srcParentNewSha, srcNextPath)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tancestorTree, ancestorOldSha, err := d.getTreeDirectly(dstDir.GetPath())\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t\tvar srcNextTree *TreeObjReq = nil\n\t\tfor _, t := range ancestorTree.Trees {\n\t\t\tif t.Path == srcNextName {\n\t\t\t\tsrcNextTree = &t.TreeObjReq\n\t\t\t\tsrcNextTree.Sha = srcNextTreeSha\n\t\t\t\tbreak\n\t\t\t}","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/github/driver.go#L324-L360","documentation":"In Move()'s upward-move branch, after stripping the destination prefix from the source path the remainder contains no '/' — meaning the source is a direct child of the destination (e.g. /aa/1 -> /aa/). That is a move in place with no rename component, which the tree-rewrite logic cannot express, so it errors. drivers/github/driver.go:342.","triggerScenarios":"Moving an object to a directory that is already its direct parent — dst == stdpath.Dir(src) effectively — hitting the !ok branch after strings.Cut.","commonSituations":"Drag-and-drop onto the object's own parent folder in the UI; automation generating a move to the containing directory as a no-op.","solutions":["Skip the move entirely — the object is already where the request wants it.","If a rename was intended, call Rename instead of Move.","Fix callers to filter out moves where dstDir == parent of srcObj."],"exampleFix":"// before\nMove(src=/aa/1, dst=/aa) // error: cannot move in place\n\n// after\n// no-op: already in place; or rename:\nRename(src=/aa/1, newName=\"1-renamed\")","handlingStrategy":"validation","validationCode":"if stdpath.Clean(dstDir.GetPath()) == stdpath.Dir(srcObj.GetPath()) {\n    // already a direct child of destination: nothing to do\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter out no-op moves where dst equals the source's parent.","Use Rename for name changes instead of Move.","Normalize and compare cleaned paths before calling Move."],"tags":["github","move","no-op","path-validation","go"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}