{"record":{"id":"decbf4601858e95f","repo":"jackwener/OpenCLI","slug":"favorites-button-not-found-make-sure-you-are-log-decbf4","errorCode":null,"errorMessage":"Favorites button not found - make sure you are logged in","messagePattern":"Favorites button not found - make sure you are logged in","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/tiktok/unsave.js","lineNumber":18,"sourceCode":"import { cli } from '@jackwener/opencli/registry';\ncli({\n    site: 'tiktok',\n    name: 'unsave',\n    access: 'write',\n    description: 'Remove a TikTok video from Favorites',\n    domain: 'www.tiktok.com',\n    args: [\n        { name: 'url', required: true, positional: true, help: 'TikTok video URL' },\n    ],\n    columns: ['status', 'url'],\n    pipeline: [\n        { navigate: { url: '${{ args.url }}', settleMs: 6000 } },\n        { evaluate: `(async () => {\n  const url = \\${{ args.url | json }};\n  const btn = document.querySelector('[data-e2e=\"bookmark-icon\"]') ||\n              document.querySelector('[data-e2e=\"collect-icon\"]');\n  if (!btn) throw new Error('Favorites button not found - make sure you are logged in');\n  const container = btn.closest('button') || btn.closest('[role=\"button\"]') || btn;\n  const aria = (container.getAttribute('aria-label') || '').toLowerCase();\n  if (aria.includes('add to favorites') || aria.includes('收藏')) {\n    if (!aria.includes('remove') && !aria.includes('取消')) {\n      return [{ status: 'Not in Favorites', url: url }];\n    }\n  }\n  container.click();\n  await new Promise(r => setTimeout(r, 2000));\n  return [{ status: 'Removed from Favorites', url: url }];\n})()\n` },\n    ],\n});\n","sourceCodeStart":1,"sourceCodeEnd":33,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/unsave.js#L1-L33","documentation":"This browser-pipeline error is thrown by the TikTok unsave script when neither `[data-e2e=\"bookmark-icon\"]` nor `[data-e2e=\"collect-icon\"]` can be found in the rendered page. The selectors only exist for logged-in sessions viewing a video, so their absence almost always means the session is not authenticated (or the page layout changed). The script aborts rather than guessing which DOM node to click.","triggerScenarios":"Running the unsave pipeline against a video URL while the browser session has no valid TikTok login cookie; TikTok redirecting to a login/signup wall or an 'expired session' interstitial instead of the video page; a TikTok DOM update that renames the data-e2e attributes; the 6000ms settle time elapsing before the icon is rendered (slow page load).","commonSituations":"Expired or never-provided session cookies; running the CLI in a fresh browser profile without logging in; scraping from a region/IP that triggers TikTok's login wall; TikTok A/B testing new DOM attributes so the hardcoded selectors no longer match.","solutions":["Log into TikTok in the browser profile/session used by the CLI, then retry.","Open the video URL manually and confirm the favorites (bookmark) button is visible; if the page redirects to login, fix the session first.","Increase the settle time after navigate if the page loads slowly.","If TikTok changed its markup, inspect the button's data-e2e attribute and update the querySelector fallbacks in clis/tiktok/unsave.js."],"exampleFix":"// before: selectors miss because page not logged in / attributes renamed\nconst btn = document.querySelector('[data-e2e=\"bookmark-icon\"]') ||\n            document.querySelector('[data-e2e=\"collect-icon\"]');\nif (!btn) throw new Error('Favorites button not found - make sure you are logged in');\n// after: detect login wall explicitly and give a precise message\nif (document.querySelector('[data-e2e=\"login-icon\"], [href*=\"login\"]')) {\n  throw new Error('Not logged in: TikTok redirected to login page');\n}\nconst btn = document.querySelector('[data-e2e=\"bookmark-icon\"], [data-e2e=\"collect-icon\"], [data-e2e=\"favorite-icon\"]');","handlingStrategy":"try-catch","validationCode":"// before running the pipeline, confirm the session can view the page\nconst res = await fetch(url, { headers: { cookie: sessionCookie } });\nif (!res.ok || /login|signup/.test(await res.text().then(t => t.slice(0, 2000)))) {\n  throw new Error('TikTok session is not logged in; refresh cookies before unsave');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await cli.tiktok.unsave(url);\n} catch (e) {\n  if (/Favorites button not found/.test(e.message)) {\n    console.error('Session likely logged out or DOM changed; re-login and retry');\n  } else throw e;\n}","preventionTips":["Keep the browser profile's TikTok session cookies fresh; re-login when they expire","Before batch unsaving, verify one video URL manually in the same profile","Check TikTok's DOM periodically for data-e2e attribute changes","Increase settleMs if pages load slowly in your environment"],"tags":["dom-selector","authentication","browser-automation","tiktok"],"backgroundTag":"dom-element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}