{"record":{"id":"024feb5d83053141","repo":"jackwener/OpenCLI","slug":"rate-limited-024feb","errorCode":"RATE_LIMITED","errorMessage":"RATE_LIMITED: TikTok rate limit / captcha detected","messagePattern":"RATE_LIMITED: TikTok rate limit / captcha detected","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"warning","filePath":"clis/tiktok/utils.js","lineNumber":502,"sourceCode":"  const timeoutMs = typeof opts.timeoutMs === 'number' ? opts.timeoutMs : 5000;\n  const intervalMs = typeof opts.intervalMs === 'number' ? opts.intervalMs : 200;\n  const deadline = Date.now() + timeoutMs;\n  while (Date.now() < deadline) {\n    try { if (predicate()) return true; } catch { /* swallow predicate errors */ }\n    await new Promise((r) => setTimeout(r, intervalMs));\n  }\n  return false;\n}\n\nfunction ensureLoggedInOrThrow() {\n  if (!checkLoggedIn()) {\n    throw new Error('AUTH_REQUIRED: TikTok login required');\n  }\n}\n\nfunction ensureNoRateLimitOrThrow() {\n  if (detectRateLimitPopup()) {\n    throw new Error('RATE_LIMITED: TikTok rate limit / captcha detected');\n  }\n}\n`;\n","sourceCodeStart":484,"sourceCodeEnd":506,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/utils.js#L484-L506","documentation":"ensureNoRateLimitOrThrow detects a rate-limit/captcha popup on the TikTok page and throws 'RATE_LIMITED: TikTok rate limit / captcha detected'. This typed marker lets the CLI distinguish throttling from auth or execution failures and stop hammering the endpoint.","triggerScenarios":"detectRateLimitPopup() found a captcha or rate-limit overlay on the current TikTok page — usually after too many rapid navigations or API hits from one session/IP.","commonSituations":"Tight scraping loops without delays; shared datacenter IP already flagged by TikTok; many parallel browser sessions from one account.","solutions":["Pause and wait (minutes to hours) before retrying; the popup often clears","Add delays/jitter between page loads and API calls","Switch to a residential proxy or different IP","Reduce concurrency: serialize requests from a single TikTok session"],"exampleFix":"// before\nfor (const id of ids) await scrapeOne(id); // tight loop triggers RATE_LIMITED\n// after\nfor (const id of ids) {\n  await scrapeOne(id);\n  await sleep(2000 + Math.random() * 2000); // backoff between requests\n}","handlingStrategy":"retry","validationCode":"const limited = await page.evaluate(() =>\n  !!document.querySelector('[class*=\"captcha\"], [class*=\"verify\"], iframe[src*=\"captcha\"]'));\nif (limited) throw new Error('RATE_LIMITED: back off before continuing');","typeGuard":"function isRateLimited(e) { return /RATE_LIMITED/i.test(e?.message || ''); }","tryCatchPattern":"try { await scrape(); } catch (e) {\n  if (isRateLimited(e)) {\n    await sleep(COOLDOWN_MS); // minutes, not seconds\n    return scrape();\n  }\n  throw e;\n}","preventionTips":["Add randomized delays between page loads","Reduce concurrency and serialize sessions","Rotate residential proxies","Avoid long uninterrupted scraping loops"],"tags":["rate-limit","captcha","tiktok","throttling"],"backgroundTag":"rate-limited-captcha","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}