jackwener/OpenCLI · error · Error

BUTTON_NOT_FOUND: Post button never became enabled (text not

Error message

BUTTON_NOT_FOUND: Post button never became enabled (text not registered or selectors changed)

What it means

After typing the comment text, `buildCommentScript` waits up to 4 seconds for the Post/发布/发送 button to become enabled. If it never enables (or is never found), the script calls `ensureNoRateLimitOrThrow()` and then throws `BUTTON_NOT_FOUND: Post button never became enabled ...`. Typically the typed text never registered in TikTok's React-controlled contenteditable, or a rate limit is suppressing the button state.

Source

Thrown at clis/tiktok/comment.js:79

  }

  input.focus();
  // execCommand is deprecated but still the only reliable way to inject
  // text into TikTok's contenteditable so its React tree picks up the
  // value; replicating with InputEvent fires but TikTok ignores it.
  document.execCommand('insertText', false, commentText);

  // Wait for the post button to become enabled — TikTok disables it
  // until non-empty text is detected by their input handler.
  const postReady = await waitFor(() => {
    const candidate = findButtonByText(['Post', '发布', '发送']);
    if (!candidate) return false;
    const ariaDisabled = candidate.getAttribute && candidate.getAttribute('aria-disabled');
    return !candidate.disabled && ariaDisabled !== 'true';
  }, { timeoutMs: 4000 });
  if (!postReady) {
    ensureNoRateLimitOrThrow();
    throw new Error('BUTTON_NOT_FOUND: Post button never became enabled (text not registered or selectors changed)');
  }

  const postBtn = findButtonByText(['Post', '发布', '发送']);
  postBtn.click();

  // State verification: a new comment-level-1 element should appear.
  const flipped = await waitFor(
    () => document.querySelectorAll('[data-e2e="comment-level-1"]').length > beforeCount,
    { timeoutMs: 8000 },
  );
  if (!flipped) {
    ensureNoRateLimitOrThrow();
    throw new Error('STATE_VERIFY_FAIL: comment count did not increase within 8s; comment may or may not have been recorded server-side');
  }

  ensureNoRateLimitOrThrow();

  return [{

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Check for and respect a TikTok comment rate limit — wait (minutes to hours) before retrying; the script already routes rate-limit cases through ensureNoRateLimitOrThrow first.
  2. Re-run the command; a single failed injection is often transient.
  3. Simplify the comment text (plain ASCII, no leading/trailing whitespace) to rule out injection/encoding issues.
  4. Verify in a headed browser that typing manually enables the Post button; if manual typing also fails, the account/video is restricted.
  5. If buttons exist but never enable, TikTok changed the button markup/labels — update the selector/text list in buildCommentScript.
Defensive patterns

Strategy: try-catch

Validate before calling

// avoid predictable automation: non-empty plain text, sane pacing
const safeText = text.trim();
if (!safeText) throw new Error('comment text is empty');
await enforceMinInterval(accountId, 60 * 1000); // keep >1 min between comments per account

Try / catch

try {
  await tiktok.comment({ url: videoUrl, text });
} catch (e) {
  if (String(e.message).startsWith('BUTTON_NOT_FOUND') && /Post button/.test(e.message)) {
    if (await isRateLimited(accountId)) {
      await sleep(minutes(30)); // cool-down then requeue
      return queueComment(accountId, videoUrl, text);
    }
    return { skipped: true, reason: 'post-button-never-enabled' };
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling `tiktok comment` when execCommand text injection didn't trigger TikTok's React state so the Post button stays disabled; the comment text is empty or only whitespace after injection; TikTok is rate-limiting the account's commenting; the button's selector/label changed in a frontend update.

Common situations: Commenting repeatedly in a short window (account soft-limited by TikTok); special characters or emoji breaking the injection; headless browser where contenteditable focus/insert events don't propagate; TikTok redesign renaming button labels or aria-disabled semantics.

Related errors


AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29). Data as JSON: /api/errors/9c118f64a074806a. Report an issue: GitHub.