{"record":{"id":"fa4f692f4797d7e3","repo":"jackwener/OpenCLI","slug":"amazon-search-did-not-expose-any-product-cards","errorCode":null,"errorMessage":"amazon search did not expose any product cards","messagePattern":"amazon search did not expose any product cards","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/amazon/search.js","lineNumber":81,"sourceCode":"        },\n        {\n            name: 'limit',\n            type: 'int',\n            default: 20,\n            help: 'Maximum number of results to return (default 20)',\n        },\n    ],\n    columns: ['rank', 'asin', 'title', 'price_text', 'rating_value', 'review_count'],\n    func: async (page, kwargs) => {\n        const query = String(kwargs.query ?? '');\n        const limit = Math.max(1, Number(kwargs.limit) || 20);\n        const payload = await readSearchPayload(page, query);\n        const sourceUrl = cleanText(payload.href) || buildSearchUrl(query);\n        const cards = (payload.cards ?? [])\n            .filter((card) => cleanText(card.asin) && cleanText(card.title))\n            .slice(0, limit);\n        if (cards.length === 0) {\n            throw new CommandExecutionError('amazon search did not expose any product cards', 'The search page may have changed or hit a robot check. Open the same query in Chrome, verify the page is visible, and retry.');\n        }\n        return cards.map((card, index) => normalizeSearchCandidate(card, index + 1, sourceUrl));\n    },\n});\nexport const __test__ = {\n    normalizeSearchCandidate,\n};\n","sourceCodeStart":63,"sourceCodeEnd":89,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/amazon/search.js#L63-L89","documentation":"Thrown when the amazon search command fetched the search results page but found no product cards with both a valid ASIN and title after filtering. Since Amazon search always renders product cards for real queries, zero cards indicates the page changed, the query returned nothing usable, or a bot-detection interstitial replaced the results.","triggerScenarios":"`opencli amazon search <query>` where the rendered page has no cards passing the (asin && title) filter; robot check page; region redirect to a page with different markup; misspelled/unicode query that yields a no-results page styled differently.","commonSituations":"Running from a cloud/VPN IP flagged by Amazon; query in a language the marketplace doesn't support; Amazon markup update breaking card extraction; sponsored-only layouts the parser can't read.","solutions":["Open the same query in Chrome and verify product cards are visible, then retry","Simplify or rephrase the search query","Retry from a residential IP or after clearing the robot check","Upgrade the library if Amazon changed search-result markup"],"exampleFix":"// before\nopencli amazon search 'q=#$%'\n// after\nopencli amazon search 'wireless earbuds'","handlingStrategy":"validation","validationCode":"if (!query || !query.trim()) throw new Error('search query must be non-empty');","typeGuard":"const hasCards = (payload) => Array.isArray(payload?.cards) && payload.cards.some((c) => c?.asin && c?.title);","tryCatchPattern":"try {\n  const results = await amazonSearch({ query });\n} catch (err) {\n  if (err.message.includes('did not expose any product cards')) {\n    // rephrase query or check for robot check, retry\n  } else throw err;\n}","preventionTips":["Test the query in Chrome first to confirm visible results","Use simple, marketplace-supported query strings","Run from residential IPs","Retry with backoff rather than hammering"],"tags":["scraping","empty-result","robot-check"],"backgroundTag":"empty-scrape-result","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}