AlistGo/alist · error

failed to decode rename response: %w

Error message

failed to decode rename response: %w

What it means

The rename response body (on a 200) could not be JSON-decoded into RenameResponse. Proton normally returns {Code, Response...} JSON, so a decode failure means the body was not Proton JSON — typically an HTML error page from an intercepting proxy, Cloudflare, or a captive portal, or an empty/truncated body.

Source

Thrown at drivers/proton_drive/util.go:662

	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)
	//fmt.Printf("DEBUG Move Request - ParentLinkID: %s\n", req.ParentLinkID)

	//fmt.Printf("DEBUG Move Request - Name length: %d\n", len(req.Name))
	//fmt.Printf("DEBUG Move Request - NameSignatureEmail: %s\n", req.NameSignatureEmail)
	//fmt.Printf("DEBUG Move Request - ContentHash: %v\n", req.ContentHash)

View on GitHub (pinned to 843d9dc814)

Solutions

  1. Capture the raw body (tee it) before decoding to see what was actually returned
  2. Bypass TLS-inspecting proxies for the Proton API host
  3. Retry on truncation — it is usually transient
  4. If HTML is consistently returned, the endpoint is being blocked; fix the network path

Example fix

// before
if err := json.NewDecoder(resp.Body).Decode(&renameResp); err != nil {
// after
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if err := json.Unmarshal(body, &renameResp); err != nil {
	return fmt.Errorf("failed to decode rename response (%q): %w", truncate(body, 200), err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// sanity check before decode is not possible remotely; guard by checking content type
if ct := resp.Header.Get("Content-Type"); ct != "" && !strings.Contains(ct, "json") {
    return fmt.Errorf("unexpected content-type %s from rename endpoint", ct)
}

Try / catch

if err := d.Rename(ctx, src, newName); err != nil {
    var syn *json.SyntaxError
    if errors.As(err, &syn) {
        // non-JSON body: proxy/middlebox interference — check network path, then retry
    }
}

Prevention

When it happens

Trigger: TLS-intercepting middlebox answering 200 with HTML; connection closed early truncating the JSON; Content-Encoding mismatch; unexpected empty body on some gateway errors.

Common situations: Corporate proxies and antivirus TLS inspection; flaky mobile links where the body is cut off; CDN edge nodes serving a soft-block page that still returns 200.

Understand the failure class

Related errors


AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15). Data as JSON: /api/errors/78454af916f618ff. Report an issue: GitHub.