{"record":{"id":"faba327c3510dd47","repo":"AlistGo/alist","slug":"rename-api-call-failed-w","errorCode":null,"errorMessage":"rename API call failed: %w","messagePattern":"rename API call failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/proton_drive/util.go","lineNumber":616,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to generate new hash: %w\", err)\n\t}\n\n\toriginalHash, err := d.getOriginalNameHash(srcLink)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to get original hash: %w\", err)\n\t}\n\n\trenameReq := RenameRequest{\n\t\tName:               encryptedName,\n\t\tNameSignatureEmail: d.MainShare.Creator,\n\t\tHash:               newHash,\n\t\tOriginalHash:       originalHash,\n\t}\n\n\terr = d.executeRenameAPI(ctx, srcLink.LinkID, renameReq)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"rename API call failed: %w\", err)\n\t}\n\n\treturn &model.Object{\n\t\tName:     newName,\n\t\tSize:     srcObj.GetSize(),\n\t\tModified: srcObj.ModTime(),\n\t\tIsFolder: srcObj.IsDir(),\n\t}, nil\n}\n\nfunc (d *ProtonDrive) executeRenameAPI(ctx context.Context, linkID string, req RenameRequest) error {\n\n\trenameURL := fmt.Sprintf(d.apiBase+\"/drive/v2/volumes/%s/links/%s/rename\",\n\t\td.MainShare.VolumeID, linkID)\n\n\treqBody, err := json.Marshal(req)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal rename request: %w\", err)","sourceCodeStart":598,"sourceCodeEnd":634,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/proton_drive/util.go#L598-L634","documentation":"Umbrella error for any failure of executeRenameAPI during Rename. It wraps one of: HTTP request construction, transport failure, non-200 status, response decode failure, or a Proton API code other than 1000. Inspect the wrapped error (%w chain) to tell which stage failed.","triggerScenarios":"PUT {apiBase}/drive/v2/volumes/{VolumeID}/links/{LinkID}/rename returning 401 (expired access token, since this raw http.Client path never refreshes tokens), 429 rate limit, 403, or body code != 1000 (hash mismatch, duplicate name).","commonSituations":"Long-lived mounts whose Proton access token expired (no refresh on this code path); aggressive scripted renames hitting rate limits; renamed-while-offline clients with stale OriginalHash; wrong appversion/sdk headers after a Proton API change.","solutions":["Check errors.Unwrap chain / response status: 401 -> refresh credentials via the authenticated proton client before retrying","429 -> back off and retry with the Retry-After header","If code != 1000 indicates hash mismatch, re-fetch the link and recompute hashes (see errors 980/987)","Route renames through the official proton-go client instead of the raw HTTP path so token refresh and error codes are handled"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := d.Rename(ctx, src, newName)\nfor attempts := 0; isRetryableRenameErr(err) && attempts < 2; attempts++ {\n    time.Sleep(backoff(attempts))\n    err = d.Rename(ctx, src, newName)\n}\nfunc isRetryableRenameErr(err error) bool {\n    return errors.Is(err, context.DeadlineExceeded) ||\n        strings.Contains(err.Error(), \"status 429\") ||\n        strings.Contains(err.Error(), \"status 401\") // after token refresh\n}","preventionTips":["Refresh Proton credentials on 401 before retrying","Honor Retry-After on 429; batch renames with pacing","Inspect the wrapped error chain rather than matching the umbrella string"],"tags":["proton-drive","rename","http","api"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}