{"record":{"id":"88289f9f2fb1d43a","repo":"fish2018/pansou","slug":"s-api-success-v-code-s","errorCode":null,"errorMessage":"[%s] API返回错误: success=%v, code=%s","messagePattern":"\\[(.+?)\\] API返回错误: success=(.+?), code=(.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/nsgame/nsgame.go","lineNumber":184,"sourceCode":"\tif resp.StatusCode != 200 {\n\t\treturn nil, fmt.Errorf(\"[%s] 请求返回状态码: %d\", p.Name(), resp.StatusCode)\n\t}\n\n\t// 6. 读取响应体\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] 读取响应失败: %w\", p.Name(), err)\n\t}\n\n\t// 7. 解析JSON响应\n\tvar apiResp NSGameResponse\n\tif err := json.Unmarshal(body, &apiResp); err != nil {\n\t\treturn nil, fmt.Errorf(\"[%s] JSON解析失败: %w\", p.Name(), err)\n\t}\n\n\t// 8. 检查响应状态\n\tif !apiResp.Success || (apiResp.Code != \"\" && apiResp.Code != \"200\") {\n\t\treturn nil, fmt.Errorf(\"[%s] API返回错误: success=%v, code=%s\", p.Name(), apiResp.Success, apiResp.Code)\n\t}\n\n\t// 9. 转换为标准格式\n\titems := apiResp.Data.PageData.Data\n\tvar results []model.SearchResult\n\tvar wg sync.WaitGroup\n\tvar mu sync.Mutex\n\tsem := make(chan struct{}, 8)\n\tfor _, item := range items {\n\t\titem := item\n\t\tif item.ID == 0 {\n\t\t\tcontinue\n\t\t}\n\t\twg.Add(1)\n\t\tsem <- struct{}{}\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tdefer func() { <-sem }()","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/nsgame/nsgame.go#L166-L202","documentation":"The search API responded with parseable JSON, but its business status is a failure: success is false, or the code field is present and not \"200\". This is the API's own error envelope — transport and parsing succeeded, the backend rejected or failed the query.","triggerScenarios":"API returns {\"success\":false,...} for an invalid/expired session, a blocked query keyword, server-side rate limiting expressed in the envelope, or an internal backend error with a non-200 code string.","commonSituations":"Anti-bot session cookie expired mid-run causing the API to report failure; query keyword triggered server-side filtering; upstream service degraded and returns code \"500\" in the JSON body with HTTP 200.","solutions":["Include the API's msg/message field in the error to learn why it failed","Refresh the anti-bot session (ensureSession) and retry once when success=false","Log apiResp.Code plus any message field to distinguish auth/session failure from backend error","If code is a rate-limit code, back off and retry with jitter","Treat persistent success=false as a site/API change and re-check the upstream contract"],"exampleFix":"// before\nif !apiResp.Success || (apiResp.Code != \"\" && apiResp.Code != \"200\") {\n    return nil, fmt.Errorf(\"[%s] API返回错误: success=%v, code=%s\", p.Name(), apiResp.Success, apiResp.Code)\n}\n// after\nif !apiResp.Success || (apiResp.Code != \"\" && apiResp.Code != \"200\") {\n    return nil, fmt.Errorf(\"[%s] API返回错误: success=%v, code=%s, msg=%s\", p.Name(), apiResp.Success, apiResp.Code, apiResp.Msg)\n}","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := plugin.Search(keyword, ext)\nif err != nil && strings.Contains(err.Error(), \"API返回错误\") {\n    log.Info(\"nsgame business error, falling back\", \"err\", err)\n    return fallbackSources.Search(keyword, ext)\n}","preventionTips":["Treat success=false as retryable-once after session refresh, then permanent","Surface the API's message field so failures are diagnosable","Back off on rate-limit-style codes instead of hammering","Track upstream API contract changes with periodic smoke tests"],"tags":["api","business-error","go","upstream"],"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"}