{"record":{"id":"8f2bc6800600ce03","repo":"jackwener/OpenCLI","slug":"state-verify-fail-comment-count-did-not-increase","errorCode":null,"errorMessage":"STATE_VERIFY_FAIL: comment count did not increase within 8s; comment may or may not have been recorded server-side","messagePattern":"STATE_VERIFY_FAIL: comment count did not increase within 8s; comment may or may not have been recorded server-side","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"clis/tiktok/comment.js","lineNumber":92,"sourceCode":"    const ariaDisabled = candidate.getAttribute && candidate.getAttribute('aria-disabled');\n    return !candidate.disabled && ariaDisabled !== 'true';\n  }, { timeoutMs: 4000 });\n  if (!postReady) {\n    ensureNoRateLimitOrThrow();\n    throw new Error('BUTTON_NOT_FOUND: Post button never became enabled (text not registered or selectors changed)');\n  }\n\n  const postBtn = findButtonByText(['Post', '发布', '发送']);\n  postBtn.click();\n\n  // State verification: a new comment-level-1 element should appear.\n  const flipped = await waitFor(\n    () => document.querySelectorAll('[data-e2e=\"comment-level-1\"]').length > beforeCount,\n    { timeoutMs: 8000 },\n  );\n  if (!flipped) {\n    ensureNoRateLimitOrThrow();\n    throw new Error('STATE_VERIFY_FAIL: comment count did not increase within 8s; comment may or may not have been recorded server-side');\n  }\n\n  ensureNoRateLimitOrThrow();\n\n  return [{\n    url: location.href,\n    text: commentText,\n    result: 'posted',\n  }];\n})()\n`;\n}\n\nasync function postComment(page, args) {\n    const { url } = parseTikTokVideoUrl(args.url);\n    const text = requireCommentText(args.text);\n    const throwFailure = (error) => throwButtonWalkerError(error, {\n        authMessage: 'TikTok requires login to post comments',","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/tiktok/comment.js#L74-L110","documentation":"buildCommentScript polls the DOM inside the TikTok page for 8 seconds waiting for the top-level comment count to increase after a comment is submitted. If the count never increases, the library throws STATE_VERIFY_FAIL to signal that it could not confirm the comment was posted. The message deliberately notes the comment may still have been recorded server-side, since TikTok's UI can lag or fail to re-render the comment list even when the API call succeeded.","triggerScenarios":"Calling postComment (or the generated browser script) on a TikTok video where the '[data-e2e=\"comment-level-1\"]' element count does not grow within 8s — e.g. comment submitted but rendered into a collapsed/filtered list, slow page, rate-limited silently, or the selector changed after a TikTok UI update.","commonSituations":"Posting many comments in quick succession so TikTok soft-throttles rendering; posting on videos with 'filtered comments' (only author-approved comments shown); running on a slow/proxied browser session where the 8s timeout is too short; TikTok shipping a DOM update that breaks the data-e2e selector.","solutions":["Wait a few seconds and re-fetch the video's comments via the API to check whether the comment actually landed before retrying — do not blindly repost or you may double-comment.","Retry the comment once after a short delay; if the text is identical, check for duplicates first.","Slow down posting cadence and add jitter between comments to avoid soft rate limiting.","If it reproduces across all videos, verify the page still contains '[data-e2e=\"comment-level-1\"]' elements (TikTok may have changed the attribute) and update the selector."],"exampleFix":"// before\nconst flipped = await waitFor(\n  () => document.querySelectorAll('[data-e2e=\"comment-level-1\"]').length > beforeCount,\n  { timeoutMs: 8000 },\n);\n// after\nconst flipped = await waitFor(\n  () => document.querySelectorAll('[data-e2e=\"comment-level-1\"]').length > beforeCount,\n  { timeoutMs: 20000 }, // allow slow renders / throttled comment lists\n);","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// STATE_VERIFY_FAIL is ambiguous: verify before retrying to avoid duplicates\ntry {\n  await postComment(videoUrl, text);\n} catch (e) {\n  if (String(e.message).startsWith('STATE_VERIFY_FAIL')) {\n    const existing = await listComments(videoUrl);\n    if (!existing.some(c => c.text === text)) {\n      await sleep(3000);\n      await postComment(videoUrl, text);\n    }\n  } else throw e;\n}","preventionTips":["Keep a local record of posted comment texts and check before retrying.","Space out comment submissions to avoid soft rate limiting.","Run on a stable, non-proxied browser session with adequate resources.","After a failure, verify server-side via the comments API rather than assuming failure."],"tags":["tiktok","timeout","dom-verification","browser-automation"],"backgroundTag":"state-verify-timeout","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}