{"record":{"id":"29e1abdc9f3e92ee","repo":"fish2018/pansou","slug":"api-returned-error-s-29e1ab","errorCode":null,"errorMessage":"api returned error: %s","messagePattern":"api returned error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/melost/melost.go","lineNumber":191,"sourceCode":"\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"unexpected status code: %d\", resp.StatusCode)\n\t}\n\n\trespBody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"read response failed: %w\", err)\n\t}\n\n\tvar apiResp MelostResponse\n\tif err := json.Unmarshal(respBody, &apiResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"decode response failed: %w\", err)\n\t}\n\n\tif apiResp.Code != 200 {\n\t\treturn nil, fmt.Errorf(\"api returned error: %s\", apiResp.Msg)\n\t}\n\n\treturn apiResp.Data.List, nil\n}\n\nfunc (p *MelostAsyncPlugin) deduplicateItems(items []MelostItem) []MelostItem {\n\tuniqueMap := make(map[string]MelostItem)\n\n\tfor _, item := range items {\n\t\tkey := item.DiskID\n\t\tif key == \"\" {\n\t\t\tkey = item.Link\n\t\t}\n\t\tif key == \"\" {\n\t\t\tkey = item.DiskName + \"|\" + item.DiskType\n\t\t}\n\n\t\texisting, exists := uniqueMap[key]","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/melost/melost.go#L173-L209","documentation":"After successful decoding, searchPage checks the application-level code in MelostResponse; if apiResp.Code != 200 it returns \"api returned error: %s\" with the API's Msg field. This is a business-logic error from the melost.cn API itself: the HTTP layer succeeded but the API refused the search (invalid params, quota, auth ticket, or captcha required).","triggerScenarios":"melost.cn responds 200 with an envelope whose code is not 200 (e.g. rate-limit code, missing/invalid search_ticket, required captcha/search_code, or query rejected), and Msg carries the API's reason.","commonSituations":"Search quota exhausted for the client/IP, the API now requires a valid search_ticket or search_code (anti-bot escalation), invalid parameter combination rejected by the backend, or empty/over-filtered queries flagged server-side.","solutions":["Read apiResp.Msg in the error text — the API states the exact reason (quota, ticket, captcha)","If Msg indicates captcha/ticket, populate adv_params.search_code or obtain a fresh search_ticket before searching","Reduce request frequency/concurrency if the code indicates rate limiting","Re-check the request parameter contract against the current melost.cn frontend to find rejected fields","Since doSearch only surfaces this when all pages fail, verify whether the code applies to specific pages only"],"exampleFix":"// before: message only\nif apiResp.Code != 200 {\n\treturn nil, fmt.Errorf(\"api returned error: %s\", apiResp.Msg)\n}\n// after: include code for programmatic handling\nif apiResp.Code != 200 {\n\treturn nil, fmt.Errorf(\"api returned error: code=%d msg=%s\", apiResp.Code, apiResp.Msg)\n}","handlingStrategy":"try-catch","validationCode":"// validate inputs the API is known to reject before calling\nif strings.TrimSpace(keyword) == \"\" {\n\treturn nil, fmt.Errorf(\"keyword required\")\n}","typeGuard":null,"tryCatchPattern":"if apiResp.Code != 200 {\n\tswitch {\n\tcase strings.Contains(apiResp.Msg, \"ticket\") || strings.Contains(apiResp.Msg, \"验证\"):\n\t\t// refresh search_ticket / handle captcha, then retry\n\tcase strings.Contains(apiResp.Msg, \"频繁\") || strings.Contains(apiResp.Msg, \"limit\"):\n\t\t// back off; rate limited\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"api returned error: %s\", apiResp.Msg)\n\t}\n}","preventionTips":["Always log the API's Msg and code for actionable diagnosis","Maintain a fresh search_ticket/search_code flow if the API requires one","Rate-limit and back off based on the API's quota messages","Track schema/message changes from melost.cn to catch new rejection reasons"],"tags":["api","business-logic","scraping","rate-limit"],"backgroundTag":"api-error-response","analyzedSha":"beaa56133755a548ebc51b090b3816e2ae044aa6","analyzedAt":"2026-09-07T00:31:18.025Z","contentChangedAt":"2026-09-07T00:31:18.025Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}