{"record":{"id":"114c87cd97e9d4cd","repo":"jackwener/OpenCLI","slug":"tiktok-returned-no-live-streams","errorCode":null,"errorMessage":"TikTok returned no live streams","messagePattern":"TikTok returned no live streams","errorType":"exception","errorClass":"EmptyResultError","httpStatus":null,"severity":"warning","filePath":"clis/tiktok/live.js","lineNumber":120,"sourceCode":"`;\n}\n\nasync function listLive(page, args) {\n    const limit = requireLimit(args.limit, { fallback: DEFAULT_LIMIT, max: MAX_LIMIT });\n    await page.goto('https://www.tiktok.com/live', { waitUntil: 'load', settleMs: 5000 });\n    let rows;\n    try {\n        rows = await page.evaluate(buildLiveScript(limit));\n    } catch (error) {\n        throwTikTokPageContextError(error, {\n            authMessage: 'TikTok requires browser access to load live streams',\n            emptyPattern: /No live streams returned/,\n            emptyTarget: 'tiktok live',\n            failureMessage: 'Failed to load TikTok live streams',\n        });\n    }\n    if (!Array.isArray(rows) || rows.length === 0) {\n        throw new EmptyResultError('tiktok live', 'TikTok returned no live streams');\n    }\n    return rows;\n}\n\nexport const liveCommand = cli({\n    site: 'tiktok',\n    name: 'live',\n    access: 'read',\n    description: 'Browse TikTok live streams via page-context APIs',\n    domain: 'www.tiktok.com',\n    strategy: Strategy.COOKIE,\n    browser: true,\n    args: [\n        { name: 'limit', type: 'int', default: DEFAULT_LIMIT, help: `Number of streams (max ${MAX_LIMIT})` },\n    ],\n    columns: ['index', 'streamer', 'name', 'title', 'viewers', 'likes', 'secUid', 'url'],\n    func: listLive,\n});","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/live.js#L102-L138","documentation":"listLive's final guard: after the page script returns, if rows is not a non-empty array the library throws EmptyResultError('tiktok live', 'TikTok returned no live streams'). It guarantees a typed empty-result error rather than returning an empty success value.","triggerScenarios":"The injected script returned null/undefined or an empty array — live-discover produced zero streams or the response shape changed so no rows were normalized.","commonSituations":"No live streams available in the account's region at query time; TikTok A/B changes to the live-discover payload breaking the normalizer; upstream API degraded to empty payloads.","solutions":["Catch EmptyResultError and treat it as an empty stream list.","Retry later — live availability is highly time-dependent.","Verify tiktok.com/live renders streams in a browser for the same session to rule out region/session issues.","Upgrade the library if TikTok changed the live-discover response shape.","Check for rate limiting or bot-walls if the empty result is persistent."],"exampleFix":"// before\nconst rows = await liveCommand({ limit: 20 });\n// after\ntry {\n  rows = await liveCommand({ limit: 20 });\n} catch (e) {\n  if (e instanceof EmptyResultError) rows = [];\n  else throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isEmptyResult(e) {\n  return e instanceof EmptyResultError;\n}","tryCatchPattern":"let rows = [];\ntry {\n  rows = await liveCommand({ limit });\n} catch (e) {\n  if (e instanceof EmptyResultError) rows = [];\n  else throw e;\n}","preventionTips":["Treat EmptyResultError for live as an empty-at-this-moment list","Retry on a schedule — live availability changes constantly","Keep the library updated for live-discover response changes","Rule out region/session issues by checking tiktok.com/live manually"],"tags":["tiktok","live","empty-result","emptyresulterror"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}