AlistGo/alist · error
failed to decode move response: %w
Error message
failed to decode move response: %w
What it means
The move response body failed to JSON-decode. Critically, unlike the rename path, executeMoveAPI never checks resp.StatusCode before decoding — so a 401/429/500 HTML or JSON error body is decoded as if it were the success envelope, and this decode error is what surfaces, masking the real status.
Source
Thrown at drivers/proton_drive/util.go:722
}
httpReq.Header.Set("Authorization", "Bearer "+d.credentials.AccessToken)
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("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(httpReq)
if err != nil {
return fmt.Errorf("failed to execute move request: %w", err)
}
defer resp.Body.Close()
var moveResp RenameResponse
if err := json.NewDecoder(resp.Body).Decode(&moveResp); err != nil {
return fmt.Errorf("failed to decode move response: %w", err)
}
if moveResp.Code != 1000 {
return fmt.Errorf("move operation failed with code: %d", moveResp.Code)
}
return nil
}
func (d *ProtonDrive) DirectMove(ctx context.Context, srcObj model.Obj, dstDir model.Obj) (model.Obj, error) {
//fmt.Printf("DEBUG DirectMove: srcPath=%s, dstPath=%s", srcObj.GetPath(), dstDir.GetPath())
srcLink, err := d.searchByPath(ctx, srcObj.GetPath(), srcObj.IsDir())
if err != nil {
return nil, fmt.Errorf("failed to find source: %w", err)
}
var dstParentLinkID stringView on GitHub (pinned to 843d9dc814)
Solutions
- Add a status check before decoding (mirror executeRenameAPI) so the true status is reported
- Log the raw body on decode failure
- Fix network interception if HTML bodies appear
Example fix
// before
var moveResp RenameResponse
if err := json.NewDecoder(resp.Body).Decode(&moveResp); err != nil {
// after
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
return fmt.Errorf("move failed with status %d: %s", resp.StatusCode, body)
}
var moveResp RenameResponse
if err := json.NewDecoder(resp.Body).Decode(&moveResp); err != nil { Defensive patterns
Strategy: try-catch
Try / catch
var syn *json.SyntaxError
var un *json.UnmarshalTypeError
if errors.As(err, &syn) || errors.As(err, &un) {
// decode failure may actually be a masked non-200 (no status check in driver):
// check token freshness and network path, then retry once
} Prevention
- Patch executeMoveAPI to check resp.StatusCode before decoding — upstream masks auth/rate-limit errors as decode errors
- Refresh credentials proactively so 401 JSON never reaches the decoder
When it happens
Trigger: Any non-200 response whose body is HTML (proxy/Cloudflare) or an error JSON that does not fit RenameResponse; empty body from gateway errors; truncated body on flaky links.
Common situations: Expired token producing a 401 error JSON that the struct cannot absorb; middleboxes answering with HTML; backend 5xx pages — all misreported as 'failed to decode move response'.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- [doubao_new] decode response failed (status: %s, content-typ
- rename API call failed: %w
- failed to marshal rename request: %w
- failed to create HTTP request: %w
- failed to execute rename request: %w
AI-assisted analysis of AlistGo/alist@843d9dc814 (2026-08-15).
Data as JSON: /api/errors/9df77a4e8a0f5aae.
Report an issue: GitHub.