{"record":{"id":"68684b766c3fb96a","repo":"fish2018/pansou","slug":"scraper","errorCode":null,"errorMessage":"重新登录后未找到scraper实例","messagePattern":"重新登录后未找到scraper实例","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"plugin/gying/gying.go","lineNumber":2405,"sourceCode":"\n\t// 检测是否为403错误\n\tif err != nil && strings.Contains(err.Error(), \"403\") {\n\t\tif DebugLog {\n\t\t\tfmt.Printf(\"[Gying] ⚠️  检测到403错误，尝试重新登录用户 %s\\n\", user.Username)\n\t\t}\n\n\t\t// 尝试重新登录\n\t\tif reloginErr := p.reloginUser(user); reloginErr != nil {\n\t\t\tif DebugLog {\n\t\t\t\tfmt.Printf(\"[Gying] ❌ 重新登录失败: %v\\n\", reloginErr)\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"403错误且重新登录失败: %w\", reloginErr)\n\t\t}\n\n\t\t// 获取新的scraper实例\n\t\tscraperVal, exists := p.scrapers.Load(user.Hash)\n\t\tif !exists {\n\t\t\treturn nil, fmt.Errorf(\"重新登录后未找到scraper实例\")\n\t\t}\n\n\t\tnewScraper, ok := scraperVal.(*cloudscraper.Scraper)\n\t\tif !ok || newScraper == nil {\n\t\t\treturn nil, fmt.Errorf(\"重新登录后scraper实例无效\")\n\t\t}\n\n\t\t// 使用新scraper重试搜索\n\t\tif DebugLog {\n\t\t\tfmt.Printf(\"[Gying] 🔄 使用新登录状态重试搜索\\n\")\n\t\t}\n\t\tresults, err = p.searchWithScraper(keyword, newScraper)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"重新登录后搜索仍然失败: %w\", err)\n\t\t}\n\t\tif syncErr := p.syncUserCookiesFromScraper(user, newScraper); syncErr != nil && DebugLog {\n\t\t\tfmt.Printf(\"[Gying] ⚠️  重登搜索后同步用户 %s Cookie失败: %v\\n\", user.Username, syncErr)\n\t\t}","sourceCodeStart":2387,"sourceCodeEnd":2423,"githubUrl":"https://github.com/fish2018/pansou/blob/beaa56133755a548ebc51b090b3816e2ae044aa6/plugin/gying/gying.go#L2387-L2423","documentation":"Internal invariant error: after a successful re-login triggered by a 403, the code looks up the fresh *cloudscraper.Scraper in p.scrapers by user.Hash and it is missing. reloginUser reported success (it should have Store()d the scraper), yet the map lookup failed.","triggerScenarios":"p.scrapers.Load(user.Hash) returns exists=false right after reloginUser succeeded — e.g. user.Hash was mutated concurrently, the map entry was deleted by another goroutine, or reloginUser stored under a different hash.","commonSituations":"Concurrent requests for the same user where one path clears/replaces scrapers; user record (Hash) changed between relogin and lookup; race conditions under high concurrency.","solutions":["Retry the request; this is often a transient race.","Check for concurrent code paths that delete or overwrite p.scrapers entries for the user.","Ensure user.Hash is stable and matches the key used in reloginUser's Store call.","Report as a bug if reproducible: reloginUser succeeded but did not store under the expected hash."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"results, err := p.Search(keyword)\nif err != nil && strings.Contains(err.Error(), \"未找到scraper实例\") {\n    time.Sleep(time.Second)\n    results, err = p.Search(keyword) // transient race usually resolves on retry\n}","preventionTips":["Serialize requests per user or protect p.scrapers with a lock.","Treat user.Hash as immutable while a re-login cycle is in flight.","Report persistent occurrences as a plugin bug."],"tags":["internal-state","race-condition","scraper"],"backgroundTag":"internal-invariant-violation","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"}