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

  1. Read and include resp.Body in the error so the real API code is visible
  2. On 401, refresh credentials (re-auth or use the official client's session) then retry
  3. On 429, honor Retry-After and back off
  4. 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

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.