AlistGo/alist · error
rename failed with status %d
Error message
rename failed with status %d
What it means
The rename endpoint answered with a non-200 HTTP status. The response body — which contains Proton's specific error code and message — is discarded, so the numeric status is all you get. 401 (expired token) and 429 (rate limit) are the dominant causes because this raw path never refreshes credentials.
Source
Thrown at drivers/proton_drive/util.go:657
return fmt.Errorf("failed to create HTTP request: %w", err)
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("Accept", d.protonJson)
httpReq.Header.Set("X-Pm-Appversion", d.webDriveAV)
httpReq.Header.Set("X-Pm-Drive-Sdk-Version", d.sdkVersion)
httpReq.Header.Set("X-Pm-Uid", d.credentials.UID)
httpReq.Header.Set("Authorization", "Bearer "+d.credentials.AccessToken)
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
return fmt.Errorf("failed to execute rename request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("rename failed with status %d", resp.StatusCode)
}
var renameResp RenameResponse
if err := json.NewDecoder(resp.Body).Decode(&renameResp); err != nil {
return fmt.Errorf("failed to decode rename response: %w", err)
}
if renameResp.Code != 1000 {
return fmt.Errorf("rename failed with code %d", renameResp.Code)
}
return nil
}
func (d *ProtonDrive) executeMoveAPI(ctx context.Context, linkID string, req MoveRequest) error {
//fmt.Printf("DEBUG Move Request - Name: %s\n", req.Name)
//fmt.Printf("DEBUG Move Request - Hash: %s\n", req.Hash)
//fmt.Printf("DEBUG Move Request - OriginalHash: %s\n", req.OriginalHash)View on GitHub (pinned to 843d9dc814)
Solutions
- Read and include resp.Body in the error so the real API code is visible
- On 401, refresh credentials (re-auth or use the official client's session) then retry
- On 429, honor Retry-After and back off
- On 403, verify the account has edit rights on the containing share
Example fix
// before
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("rename failed with status %d", resp.StatusCode)
}
// after
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
return fmt.Errorf("rename failed with status %d: %s", resp.StatusCode, body)
} Defensive patterns
Strategy: try-catch
Type guard
func isRenameStatusErr(err error) (code int, ok bool) {
var n int
if _, e := fmt.Sscanf(err.Error(), "rename failed with status %d", &n); e == nil { return n, true }
return 0, false
} Try / catch
if code, ok := isRenameStatusErr(err); ok {
switch code {
case 401: refreshCreds(); retry()
case 429: sleep(retryAfter); retry()
case 403: return fmt.Errorf("no edit permission")
default: return err
}
} Prevention
- Refresh access tokens proactively before expiry on long-lived mounts
- Patch the driver to include the response body in status errors so diagnosis is possible
When it happens
Trigger: Expired AccessToken after long uptime (401); too many renames in a burst (429 with Retry-After); insufficient permission on a shared item (403); API route changed after a Proton backend update (404/410).
Common situations: Mounts running for days on one token; bulk rename scripts; renaming inside a share where the account only has viewer rights; Proton API version bumps breaking the hardcoded /drive/v2 path.
Related errors
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/8c240e8c3ad8ad76.
Report an issue: GitHub.