{"record":{"id":"1e01bacc40a39cfd","repo":"jackwener/OpenCLI","slug":"no-videos-found-on-explore-suffix","errorCode":null,"errorMessage":"No videos found on /explore + suffix","messagePattern":"No videos found on /explore \\+ suffix","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/tiktok/explore.js","lineNumber":120,"sourceCode":"    }\n  }\n  if (dedup.size < limit) {\n    try {\n      // Keep the previous recommend feed as a compatibility fallback for\n      // regions where /explore still hydrates from the For You endpoint.\n      await collectEndpoint('/api/recommend/item_list/', 'recommend', { from_page: 'fyp' }, 0);\n    } catch (error) {\n      apiFailures.push(error instanceof Error ? error.message : String(error));\n    }\n  }\n\n  const rows = Array.from(dedup.values())\n    .slice(0, limit)\n    .map((row, index) => ({ ...row, index: index + 1 }));\n\n  if (rows.length === 0) {\n    const suffix = apiFailures.length ? ' (explore APIs failed: ' + apiFailures.join('; ') + ')' : '';\n    throw new Error('No videos found on /explore' + suffix);\n  }\n  return rows;\n})()\n`;\n}\n\nasync function listExploreVideos(page, args) {\n    const limit = requireLimit(args.limit, { fallback: DEFAULT_LIMIT, max: MAX_LIMIT });\n    await page.goto('https://www.tiktok.com/explore', { waitUntil: 'load', settleMs: 5000 });\n    let rows;\n    try {\n        rows = await page.evaluate(buildExploreScript(limit));\n    } catch (error) {\n        throwTikTokPageContextError(error, {\n            authMessage: 'TikTok requires browser access to load the explore feed',\n            emptyPattern: /No videos found/,\n            emptyTarget: 'tiktok explore',\n            failureMessage: 'Failed to load TikTok explore feed',","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/explore.js#L102-L138","documentation":"The injected /explore scraping script extracted zero video rows after deduplication. When explore API fallbacks also failed, the error message appends the per-API failure reasons. Thrown inside the browser context as a plain Error with the 'No videos found on /explore' prefix.","triggerScenarios":"The /explore page (optionally with a suffix path/category) rendered no videos matching the selectors, and all explore API fallbacks either weren't attempted or failed (apiFailures non-empty adds details).","commonSituations":"TikTok showing a login wall or captcha instead of explore content, region restrictions making /explore empty, TikTok DOM/classname changes breaking the extraction selectors, or a category suffix that has no content in the current region.","solutions":["Read the appended apiFailures detail to see why the API fallbacks failed","Open /explore in the same Chrome profile and confirm videos render manually (login wall/captcha?)","Update the library — selector or API changes on TikTok's side require a patch","Try a different explore suffix/category or remove the suffix to use the default explore page","Check your region/IP — some regions return an empty explore page"],"exampleFix":"// before\nconst rows = await listExploreVideos(page, { limit: 20 });\n// after\ntry {\n  const rows = await listExploreVideos(page, { limit: 20 });\n} catch (e) {\n  if (/No videos found on \\/explore/.test(e.message)) {\n    await page.goto(TIKTOK_HOST + '/explore'); // re-warm, solve any wall\n    return listExploreVideos(page, { limit: 20 });\n  }\n  throw e;\n}","handlingStrategy":"fallback","validationCode":"await page.goto(TIKTOK_HOST + '/explore', { waitUntil: 'networkidle2' });\nconst rendered = await page.$$eval('[data-e2e=\"explore-item\"], a[href*=\"/video/\"]', els => els.length);\nif (rendered === 0) throw new Error('Explore page rendered no items — check login wall/region');","typeGuard":null,"tryCatchPattern":"try {\n  rows = await listExploreVideos(page, opts);\n} catch (e) {\n  if (/No videos found on \\/explore/.test(e.message)) {\n    // fall back to a different source, e.g. recommend feed or hashtag page\n    return fallbackVideoSource(page, opts);\n  }\n  throw e;\n}","preventionTips":["Check the appended apiFailures detail to diagnose API fallback failures","Confirm /explore renders videos manually in the same profile (no login wall/captcha)","Try removing or changing the explore suffix/category","Update selectors/library when TikTok changes its DOM","Be aware of regional differences — some regions serve empty explore pages"],"tags":["tiktok","scraping","selectors","empty-result","dom-change"],"backgroundTag":"scrape-selectors-outdated","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}