{"record":{"id":"2a446aa6614acd58","repo":"jackwener/OpenCLI","slug":"no-following-entries-returned-suffix","errorCode":null,"errorMessage":"No following entries returned + suffix","messagePattern":"No following entries returned \\+ suffix","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/tiktok/following.js","lineNumber":118,"sourceCode":"      for (const entry of list) {\n        const row = normalizeUserRow(entry?.user || entry, dedup.size + 1);\n        if (row && !dedup.has(row.username)) dedup.set(row.username, row);\n      }\n      if (data.hasMore !== true) break;\n      cursor = asNumber(data.minCursor) ?? asNumber(data.cursor) ?? cursor + list.length;\n    } catch (error) {\n      apiFailure = error instanceof Error ? error.message : String(error);\n      break;\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 = apiFailure ? ' (user-list API failed: ' + apiFailure + ')' : '';\n    throw new Error('No following entries returned' + suffix);\n  }\n  return rows;\n})()\n`;\n}\n\nasync function listFollowing(page, args) {\n    const limit = requireLimit(args.limit, { fallback: DEFAULT_LIMIT, max: MAX_LIMIT });\n    await page.goto('https://www.tiktok.com/following', { waitUntil: 'load', settleMs: 5000 });\n    let rows;\n    try {\n        rows = await page.evaluate(buildFollowingScript(limit));\n    } catch (error) {\n        throwTikTokPageContextError(error, {\n            authMessage: 'TikTok requires login to read your following list',\n            emptyPattern: /No following entries/,\n            emptyTarget: 'tiktok following',\n            failureMessage: 'Failed to load TikTok following list',","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/following.js#L100-L136","documentation":"After paging TikTok's /api/user/list (scene=21) endpoint, if zero unique following rows were collected the script throws 'No following entries returned'. If one of the page fetches failed, the underlying API error message is appended as '(user-list API failed: ...)' to explain why the list is empty. This distinguishes a genuinely empty following list from an API failure.","triggerScenarios":"The first user-list page returned an empty userList (data.hasMore !== true or list.length === 0) for an account that follows nobody; or a fetchJson/assertTikTokApiFailure error occurred on the first page, setting apiFailure, so no rows exist.","commonSituations":"New account with zero follows; TikTok API returning status != 0 (e.g. 10216 unverified request / rate code) captured in the suffix; msToken missing causing signed-request rejection; the logged-in viewer's following list region-blocked.","solutions":["Read the appended '(user-list API failed: ...)' suffix to identify the underlying API error and address that first.","Confirm the account actually follows people by checking tiktok.com/@you/following in a browser.","Refresh msToken / session cookies and retry — unsigned or stale msToken requests commonly fail.","Wait out rate limiting if the suffix shows a status-code error, then retry.","If the list is truly empty, treat this as expected behavior rather than an error."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isEmptyWithApiFailure(e) {\n  return e instanceof Error && e.message.startsWith('No following entries returned');\n}\nfunction hadApiFailure(e) { return /user-list API failed:/.test(e?.message || ''); }","tryCatchPattern":"try {\n  rows = await followingCommand({ limit });\n} catch (e) {\n  if (isEmptyWithApiFailure(e)) {\n    if (hadApiFailure(e)) warn('retry after fixing API failure: ' + e.message);\n    else rows = []; // account genuinely follows nobody\n  } else throw e;\n}","preventionTips":["Parse the '(user-list API failed: ...)' suffix to distinguish empty-list from API failure","Keep msToken fresh; signed requests fail without it","Confirm the account follows people before assuming an error","Back off and retry when the suffix shows a rate/status code error"],"tags":["tiktok","empty-result","api","pagination"],"backgroundTag":"empty-result-set","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}