{"record":{"id":"050d13f8bf62f88d","repo":"AlistGo/alist","slug":"move-operation-failed-with-code-d","errorCode":null,"errorMessage":"move operation failed with code: %d","messagePattern":"move operation failed with code: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/proton_drive/util.go","lineNumber":726,"sourceCode":"\thttpReq.Header.Set(\"X-Pm-Appversion\", d.webDriveAV)\n\thttpReq.Header.Set(\"X-Pm-Drive-Sdk-Version\", d.sdkVersion)\n\thttpReq.Header.Set(\"X-Pm-Uid\", d.credentials.UID)\n\thttpReq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tclient := &http.Client{}\n\tresp, err := client.Do(httpReq)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to execute move request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tvar moveResp RenameResponse\n\tif err := json.NewDecoder(resp.Body).Decode(&moveResp); err != nil {\n\t\treturn fmt.Errorf(\"failed to decode move response: %w\", err)\n\t}\n\n\tif moveResp.Code != 1000 {\n\t\treturn fmt.Errorf(\"move operation failed with code: %d\", moveResp.Code)\n\t}\n\n\treturn nil\n}\n\nfunc (d *ProtonDrive) DirectMove(ctx context.Context, srcObj model.Obj, dstDir model.Obj) (model.Obj, error) {\n\t//fmt.Printf(\"DEBUG DirectMove: srcPath=%s, dstPath=%s\", srcObj.GetPath(), dstDir.GetPath())\n\n\tsrcLink, err := d.searchByPath(ctx, srcObj.GetPath(), srcObj.IsDir())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to find source: %w\", err)\n\t}\n\n\tvar dstParentLinkID string\n\tif dstDir.GetPath() == \"/\" {\n\t\tdstParentLinkID = d.RootLink.LinkID\n\t} else {\n\t\tdstLink, err := d.searchByPath(ctx, dstDir.GetPath(), true)","sourceCodeStart":708,"sourceCodeEnd":744,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/proton_drive/util.go#L708-L744","documentation":"Proton returned 200 for the move but the body's Code is not 1000. The numeric code carries the real reason: invalid/expired token, invalid hashes, target-parent not writable, or passphrase re-encryption rejected (bad NodePassphrase).","triggerScenarios":"Moving into a share where the account lacks write permission; NodePassphrase re-encrypted with the wrong destination keyring; stale OriginalHash; name-hash collision (duplicate name) in the destination folder.","commonSituations":"Moves into folders shared read-only; cross-share moves where the destination parent keyring could not be derived; concurrent clients mutating the same tree; keyring/address-key drift after password reset (old keys revoked).","solutions":["Log moveResp.Code and map known codes (auth vs hash vs permission) instead of showing only the number","For hash errors, re-fetch the link, regenerate hashes and passphrase, retry once","For permission codes, fail fast with a permission error","Use the official proton-go move API which encodes these failure modes properly"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isMoveCodeErr(err error) (code int, ok bool) {\n    var n int\n    if _, e := fmt.Sscanf(err.Error(), \"move operation failed with code: %d\", &n); e == nil { return n, true }\n    return 0, false\n}","tryCatchPattern":"if code, ok := isMoveCodeErr(err); ok {\n    if isAuthCode(code) { refreshCreds(); retry() }\n    if isPermissionCode(code) { return fmt.Errorf(\"no write access to destination\") }\n    if isHashCode(code) { refetchLink(); regenerateHashesAndPassphrase(); retryOnce() }\n}","preventionTips":["Verify write permission on destination share before moving","Keep hashes and passphrase freshly computed from re-fetched links","Map Proton error codes centrally in your integration"],"tags":["proton-drive","move","api","permissions"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}