{"record":{"id":"148d7052afbad20c","repo":"fish2018/pansou","slug":"action-id-w-148d70","errorCode":null,"errorMessage":"刷新Action ID失败: %w","messagePattern":"刷新Action ID失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/panyq/panyq.go","lineNumber":217,"sourceCode":"func (p *PanyqPlugin) doSearch(client *http.Client, keyword string, ext map[string]interface{}) ([]model.SearchResult, error) {\n\tif DebugLog {\n\t\tfmt.Println(\"panyq: searching for\", keyword)\n\t}\n\n\t// 尝试获取或发现 Action ID\n\tactionIDs, err := p.getOrDiscoverActionIDs()\n\tif err != nil {\n\t\t// fmt.Println(\"panyq: failed to get Action IDs:\", err)\n\t\treturn nil, fmt.Errorf(\"获取Action ID失败: %w\", err)\n\t}\n\n\t// 步骤1: 获取搜索凭证\n\tcredentials, err := p.getCredentials(keyword, actionIDs[ActionIDKeys[0]], client)\n\tif err != nil {\n\t\t// 如果获取凭证失败，尝试刷新Action ID并重试\n\t\tactionIDs, err = p.discoverActionIDs()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"刷新Action ID失败: %w\", err)\n\t\t}\n\t\t\n\t\t// 使用新的Action ID重试获取凭证\n\t\tcredentials, err = p.getCredentials(keyword, actionIDs[ActionIDKeys[0]], client)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"获取搜索凭证失败: %w\", err)\n\t\t}\n\t}\n\n\t// 步骤2: 获取第一页搜索结果列表\n\thits, maxPageNum, err := p.getSearchResults(credentials.Sign, 1, client)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"获取搜索结果失败: %w\", err)\n\t}\n\n\tif len(hits) == 0 {\n\t\tif DebugLog {\n\t\t\tfmt.Println(\"panyq: no results found for\", keyword)","sourceCodeStart":199,"sourceCodeEnd":235,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/panyq/panyq.go#L199-L235","documentation":"When fetching search credentials with the current Action ID fails, doSearch attempts to re-discover (refresh) the Action IDs. If that refresh itself fails, the plugin gives up and wraps the discovery error as \"刷新Action ID失败\" — it cannot get credentials with either the old or refreshed IDs.","triggerScenarios":"getCredentials fails, then discoverActionIDs also errors: the discovery request fails at the transport level, the response structure changed so extraction fails, or anti-bot/rate limiting blocks the refresh request.","commonSituations":"Upstream rotated its page structure or API version; site temporarily down so both the original call and refresh fail; IP rate-limited after repeated failures; stale cached IDs expired AND discovery blocked.","solutions":["Inspect the wrapped discovery error (network vs parse) and address that root cause.","Wait and retry with backoff — simultaneous failure of both paths often indicates transient outage or rate limiting.","Update the discovery parsing logic if the upstream page structure changed.","Check IP reputation / reduce request frequency if rate limited.","Clear cached Action IDs and verify the discovery endpoint manually with curl."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Go (caller): probe the upstream endpoint before invoking search\nresp, err := http.Head(upstreamBaseURL)\nif err != nil || resp.StatusCode >= 400 {\n    return nil, fmt.Errorf(\"panyq upstream unhealthy; skip search\")\n}","typeGuard":null,"tryCatchPattern":"result, err := plugin.Search(keyword, ext)\nif err != nil && strings.Contains(err.Error(), \"刷新Action ID失败\") {\n    // both original and refreshed IDs failed; likely outage or rate limit\n    time.Sleep(backoff)\n    result, err = plugin.Search(keyword, ext)\n    if err != nil { return err }\n}","preventionTips":["Back off exponentially when both credential paths fail — it usually means an outage or IP rate limit.","Reduce search frequency to avoid triggering anti-bot limits that break discovery.","Monitor upstream site changes that rotate Action IDs.","Alert on this error as an upstream-integration breakage, not a caller bug."],"tags":["scraping","api","retry","go"],"backgroundTag":"upstream-api-error","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"}