{"record":{"id":"1decf980d9642af0","repo":"AlistGo/alist","slug":"request-failed-status-d-body-s","errorCode":null,"errorMessage":"request failed: status=%d body=%s","messagePattern":"request failed: status=(.+?) body=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"drivers/guangyapan/driver.go","lineNumber":828,"sourceCode":"func (d *GuangYaPan) postAPI(ctx context.Context, path string, body any, out any) error {\n\tif strings.TrimSpace(d.AccessToken) == \"\" {\n\t\treturn errors.New(\"access token is empty\")\n\t}\n\tif err := d.apiRateLimitWait(ctx, path); err != nil {\n\t\treturn err\n\t}\n\tresp, err := d.apiClient.R().\n\t\tSetContext(ctx).\n\t\tSetHeader(\"Authorization\", \"Bearer \"+d.AccessToken).\n\t\tSetBody(body).\n\t\tSetResult(out).\n\t\tPost(path)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif resp.StatusCode() == 401 || resp.StatusCode() == 403 {\n\t\tif strings.TrimSpace(d.RefreshToken) == \"\" {\n\t\t\treturn fmt.Errorf(\"request failed: status=%d body=%s\", resp.StatusCode(), resp.String())\n\t\t}\n\t\tif err := d.refreshToken(ctx); err != nil {\n\t\t\treturn err\n\t\t}\n\t\tresp, err = d.apiClient.R().\n\t\t\tSetContext(ctx).\n\t\t\tSetHeader(\"Authorization\", \"Bearer \"+d.AccessToken).\n\t\t\tSetBody(body).\n\t\t\tSetResult(out).\n\t\t\tPost(path)\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\t}\n\tif resp.IsError() {\n\t\treturn fmt.Errorf(\"request failed: status=%d body=%s\", resp.StatusCode(), resp.String())\n\t}\n\treturn nil","sourceCodeStart":810,"sourceCodeEnd":846,"githubUrl":"https://github.com/AlistGo/alist/blob/843d9dc8149126976b2625911e45a4d3ffd6f2f5/drivers/guangyapan/driver.go#L810-L846","documentation":"postAPI's first-line failure: a POST to api.guangyapan.com returned 401 or 403, and the storage has no RefreshToken, so automatic token refresh is impossible. The status and raw body are embedded. It indicates an unauthenticated/expired session with no recovery path configured.","triggerScenarios":"Any postAPI call (list, task status, upload token, offline ops) with expired AccessToken while RefreshToken is empty - e.g. storage configured with only an access token, or SMS login state lost its refresh token.","commonSituations":"User pasted only an access token into config; refresh token was cleared by a failed refresh; tokens from a different client_id.","solutions":["Complete a full login (SMS login with phone_number + verify_code) so both tokens are stored.","If tokens were exported from elsewhere, re-obtain them with the same ClientID the driver uses.","Confirm the account is not locked/disabled (check the embedded body for the provider's reason)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// before heavy API use, confirm auth is recoverable\nif strings.TrimSpace(d.AccessToken) == \"\" && strings.TrimSpace(d.RefreshToken) == \"\" {\n    return errors.New(\"guangyapan storage has no tokens; complete SMS login first\")\n}","typeGuard":null,"tryCatchPattern":"if err := d.postAPI(ctx, path, body, out); err != nil {\n    if strings.Contains(err.Error(), \"status=401\") || strings.Contains(err.Error(), \"status=403\") {\n        if strings.TrimSpace(d.RefreshToken) == \"\" {\n            return errors.New(\"session expired and no refresh token stored - redo SMS login\")\n        }\n    }\n    return err\n}","preventionTips":["Always complete full login so both tokens persist.","Monitor for this error as an early signal of session loss."],"tags":["auth","http-401","http-403","guangyapan"],"backgroundTag":null,"analyzedSha":"843d9dc8149126976b2625911e45a4d3ffd6f2f5","analyzedAt":"2026-08-15T12:14:11.722Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}