{"record":{"id":"b87d7ff352d24c7a","repo":"jackwener/OpenCLI","slug":"selector-b87d7f","errorCode":"SELECTOR","errorMessage":"Could not find element: window.lib.mtop","messagePattern":"Could not find element: window\\.lib\\.mtop","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"clis/xianyu/search.js","lineNumber":231,"sourceCode":"        if (minPrice != null && maxPrice != null && minPrice > maxPrice) {\n            throw new ArgumentError('xianyu search min-price cannot be greater than max-price', `Received --min-price ${minPrice} and --max-price ${maxPrice}`);\n        }\n        const province = String(kwargs.province || '').trim();\n        const city = String(kwargs.city || '').trim();\n        const searchFilter = buildSearchFilter(minPrice, maxPrice);\n        const extraFilterValue = buildExtraFilterValue(province, city);\n        const fromFilter = Boolean(searchFilter) || extraFilterValue !== '{}';\n        await page.goto(buildSearchUrl(query));\n        await page.wait(2);\n        const result = await page.evaluate(buildSearchEvaluate({ keyword: query, searchFilter, extraFilterValue, fromFilter, maxItems: limit }));\n        if (result?.error === 'auth-required') {\n            throw new AuthRequiredError('www.goofish.com', 'Xianyu search requires a logged-in browser session');\n        }\n        if (result?.error === 'blocked') {\n            throw new CommandExecutionError('Xianyu returned a verification page or blocked the current browser session');\n        }\n        if (result?.error === 'mtop-not-ready') {\n            throw selectorError('window.lib.mtop', '闲鱼页面未完成初始化，无法调用搜索接口');\n        }\n        if (!result || typeof result !== 'object') {\n            throw new CommandExecutionError('Xianyu search returned a malformed response');\n        }\n        const errorCode = String(result?.error_code || '');\n        const errorMessage = String(result?.error_message || '');\n        if (/FAIL_SYS_SESSION_EXPIRED|SESSION_EXPIRED|FAIL_SYS_TOKEN/.test(errorCode) || /FAIL_SYS_SESSION_EXPIRED|SESSION_EXPIRED/.test(errorMessage)) {\n            throw new AuthRequiredError('www.goofish.com', 'Xianyu search requires a logged-in browser session');\n        }\n        if (result?.error) {\n            throw new CommandExecutionError(errorMessage || `Xianyu search request failed: ${result.error}`);\n        }\n        if (!Array.isArray(result.items)) {\n            throw new CommandExecutionError('Xianyu search response did not include an items array');\n        }\n        const items = result.items;\n        if (!items.length) {\n            throw new EmptyResultError('xianyu search', '没有匹配的商品（筛选条件可能过窄，或当前关键词无结果）');","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xianyu/search.js#L213-L249","documentation":"selectorError thrown when the in-page mtop bridge (window.lib.mtop) is unavailable during a Xianyu search, mapped from the evaluate result error 'mtop-not-ready'. Same family as 5432 but in the search flow (clis/xianyu/search.js).","triggerScenarios":"Running a Xianyu search while the Goofish page has not initialized window.lib.mtop, so the search API call cannot be dispatched.","commonSituations":"Search page still bootstrapping due to slow network; anti-bot verification page intercepted JS init; Goofish changed the mtop global path.","solutions":["Wait for window.lib.mtop to exist (waitForFunction) before running the search evaluate","Reload the search page and retry after initialization","Handle any verification/blocked interstitial that prevents JS bootstrap","Update the evaluate's mtop access path if Goofish changed internals"],"exampleFix":"// before\nawait opencli xianyu search --q 'iphone'\n// after: warm up the page first\nawait page.waitForFunction(() => window.lib && window.lib.mtop);\nawait opencli xianyu search --q 'iphone'","handlingStrategy":"retry","validationCode":"await page.waitForFunction(() => window.lib && typeof window.lib.mtop === 'object', { timeout: 15000 });","typeGuard":"const mtopReady = () => page.evaluate(() => Boolean(window.lib && window.lib.mtop));","tryCatchPattern":"try {\n  await opencli xianyu search --q 'iphone';\n} catch (e) {\n  if (e.code === 'SELECTOR' && e.message.includes('window.lib.mtop')) {\n    await page.reload();\n    await page.waitForFunction(() => window.lib && window.lib.mtop);\n    await opencli xianyu search --q 'iphone';\n  } else throw e;\n}","preventionTips":["Gate search calls on mtop availability","Warm up the page before API-dependent commands","Handle verification pages before issuing searches","Keep the mtop access path in evaluate up to date"],"tags":["selector","xianyu","page-initialization"],"backgroundTag":"selector-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}