{"record":{"id":"6743259802bf9a3c","repo":"AlistGo/alist","slug":"merge-list-source-folder-failed-w","errorCode":null,"errorMessage":"merge: list source folder failed: %w","messagePattern":"merge: list source folder failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/sjtu_netdisk/driver.go","lineNumber":280,"sourceCode":"\t\t\treturn &model.Object{\n\t\t\t\tName:     srcObj.GetName(),\n\t\t\t\tSize:     srcObj.GetSize(),\n\t\t\t\tIsFolder: true,\n\t\t\t\tModified: srcObj.ModTime(),\n\t\t\t\tCtime:    srcObj.CreateTime(),\n\t\t\t\tPath:     targetPath,\n\t\t\t}, nil\n\t\t}\n\n\t\t// 409 means conflict name, needs merge\n\t\tif !errors.Is(err, errs.ObjectNotFound) {\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// list all child item of srcObj\n\t\tchildren, listErr := d.List(ctx, srcObj, model.ListArgs{})\n\t\tif listErr != nil {\n\t\t\treturn nil, fmt.Errorf(\"merge: list source folder failed: %w\", listErr)\n\t\t}\n\n\t\t// move every child item to dstDir recursively\n\t\tfor _, child := range children {\n\t\t\tchildSrcPath := path.Join(srcPath, child.GetName())\n\t\t\ttargetDstPath := targetPath\n\n\t\t\t// subfolder: recursive Move\n\t\t\tif child.IsDir() {\n\t\t\t\tchildErr := d.moveItem(ctx, childSrcPath, targetDstPath, child.GetName(), true, \"ask\")\n\t\t\t\tif childErr != nil && errors.Is(childErr, errs.ObjectNotFound) {\n\t\t\t\t\tchildObj := &model.Object{\n\t\t\t\t\t\tName:     child.GetName(),\n\t\t\t\t\t\tPath:     childSrcPath,\n\t\t\t\t\t\tSize:     child.GetSize(),\n\t\t\t\t\t\tIsFolder: true,\n\t\t\t\t\t}\n\t\t\t\t\t_, mergeErr := d.Move(ctx, childObj, &model.Object{","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/sjtu_netdisk/driver.go#L262-L298","documentation":"During a Move that hits a name conflict (409), the SJTU driver merges by recursively moving each child of the source folder. This error means the List call needed to enumerate those children itself failed, so the merge could not even start. The wrapped error carries the actual List failure.","triggerScenarios":"Move folder A into a location already containing A triggers the merge path; the subsequent d.List(ctx, srcObj) fails due to an expired token, the source folder being deleted mid-operation, or a transient API error.","commonSituations":"Concurrent modification (another client moved/deleted the source folder); token expiry racing the second API call; moving very large folders where the API times out on listing; the source path containing characters that break the listing URL.","solutions":["Inspect the wrapped error (%w) — it is the real cause (auth, 404, timeout)","Retry the move after confirming the source folder still lists correctly in the AList UI","Avoid concurrent moves/renames of the same tree from two clients","If the source is gone, refresh the parent directory and drop the stale entry"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"merge: list source folder failed\") {\n    // source may be stale; re-list parent, then retry the move once\n    refreshDir(srcParent)\n    return retryMoveOnce()\n}","preventionTips":["Do not modify the source tree while a merge-move is in flight","Refresh listings before moving folders cached from earlier sessions","Move large trees in subfolder batches to limit blast radius"],"tags":["sjtu-netdisk","move","merge","recursion","filesystem"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}