{"record":{"id":"eb2d163de94c71ca","repo":"jackwener/OpenCLI","slug":"button-not-found-comment-input-not-found-page-no","errorCode":null,"errorMessage":"BUTTON_NOT_FOUND: comment input not found (page not rendered, comments disabled, or selectors changed)","messagePattern":"BUTTON_NOT_FOUND: comment input not found \\(page not rendered, comments disabled, or selectors changed\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/tiktok/comment.js","lineNumber":60,"sourceCode":"  ensureLoggedInOrThrow();\n  ensureNoRateLimitOrThrow();\n\n  // Expand the comment panel if it is collapsed (vertical feed pages).\n  const commentIcon = document.querySelector('[data-e2e=\"comment-icon\"]');\n  if (commentIcon) {\n    const cBtn = commentIcon.closest('button') || commentIcon.closest('[role=\"button\"]') || commentIcon;\n    cBtn.click();\n    await waitFor(() => Boolean(\n      document.querySelector('[data-e2e=\"comment-input\"] [contenteditable=\"true\"]')\n    ), { timeoutMs: 4000 });\n  }\n\n  const beforeCount = document.querySelectorAll('[data-e2e=\"comment-level-1\"]').length;\n\n  const input = document.querySelector('[data-e2e=\"comment-input\"] [contenteditable=\"true\"]')\n    || document.querySelector('[contenteditable=\"true\"]');\n  if (!input) {\n    throw new Error('BUTTON_NOT_FOUND: comment input not found (page not rendered, comments disabled, or selectors changed)');\n  }\n\n  input.focus();\n  // execCommand is deprecated but still the only reliable way to inject\n  // text into TikTok's contenteditable so its React tree picks up the\n  // value; replicating with InputEvent fires but TikTok ignores it.\n  document.execCommand('insertText', false, commentText);\n\n  // Wait for the post button to become enabled — TikTok disables it\n  // until non-empty text is detected by their input handler.\n  const postReady = await waitFor(() => {\n    const candidate = findButtonByText(['Post', '发布', '发送']);\n    if (!candidate) return false;\n    const ariaDisabled = candidate.getAttribute && candidate.getAttribute('aria-disabled');\n    return !candidate.disabled && ariaDisabled !== 'true';\n  }, { timeoutMs: 4000 });\n  if (!postReady) {\n    ensureNoRateLimitOrThrow();","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/comment.js#L42-L78","documentation":"`buildCommentScript` runs in the page to post a TikTok comment: it locates the comment input via `[data-e2e=\"comment-input\"] [contenteditable=\"true\"]` (falling back to any contenteditable). If no input element exists it throws `BUTTON_NOT_FOUND: comment input not found ...`, an in-page Error surfaced by `postComment`. The library treats a missing input as 'cannot comment here' — the page never rendered a comment box.","triggerScenarios":"Calling `tiktok comment --url <video>` (postComment -> script) when the video page has comments disabled by the creator, the page didn't finish rendering before the script ran, the URL points to a non-video page (profile/short link that didn't resolve), or TikTok changed the data-e2e attributes/selector structure.","commonSituations":"Commenting on videos with comments turned off; slow network/first render racing the script; headless rendering stuck on a consent or login wall; TikTok A/B redesign removing `data-e2e=\"comment-input\"`; posting to a deleted/private video.","solutions":["Confirm the target video allows comments (check in a normal browser) — disabled comments make this failure permanent for that video.","Retry with a longer wait/allow the page to fully load before running the comment script, or re-run the command.","Verify the URL resolves directly to the video page (resolve short links like vm.tiktok.com first).","Check the live DOM for the comment input selector; if TikTok renamed the attributes, update the library's selectors in buildCommentScript.","Ensure you are logged in — logged-out views may not render the comment input at all."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-check: does the video allow comments?\nconst meta = await fetch(`https://www.tiktok.com/oembed?url=${encodeURIComponent(videoUrl)}`).then(r => r.json()).catch(() => null);\nif (!meta) throw new Error('URL is not a resolvable TikTok video');","typeGuard":null,"tryCatchPattern":"try {\n  await tiktok.comment({ url: videoUrl, text });\n} catch (e) {\n  if (String(e.message).startsWith('BUTTON_NOT_FOUND') && /comment input/.test(e.message)) {\n    // comments disabled / not rendered / selectors changed\n    console.warn(`Cannot comment on ${videoUrl}: comments likely disabled or page not loaded.`);\n    return { skipped: true, reason: 'comment-input-missing' };\n  }\n  throw e;\n}","preventionTips":["Filter target videos to those with comments enabled before batch commenting.","Resolve short links (vm.tiktok.com) to full video URLs first.","Wait for full page render before commenting; add a small settle delay.","After TikTok redesigns, verify data-e2e=\"comment-input\" still exists in the DOM."],"tags":["tiktok","comment","selector","dom"],"backgroundTag":"element-not-found","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}