jackwener/OpenCLI · error · CommandExecutionError

填写抖音草稿表单失败: visibility-missing

Error message

填写抖音草稿表单失败: visibility-missing

What it means

fillDraftComposer clicks a <label> whose text contains the visibility label ('公开' / '好友可见' / '仅自己可见'). If no matching label is found it throws this CommandExecutionError with reason 'visibility-missing'. The visibility section of the composer was not present or its text changed.

Source

Thrown at clis/douyin/draft.js:119

      document.execCommand('selectAll', false);
      document.execCommand('insertText', false, ${JSON.stringify(options.caption)});
      editor.dispatchEvent(new Event('input', { bubbles: true }));
      return true;
    }`));
        if (!captionOk) {
            throw new CommandExecutionError('填写抖音草稿表单失败: caption-editor-missing');
        }
    }
    const visibilityOk = (await page.evaluate(`() => {
    const visibility = Array.from(document.querySelectorAll('label')).find(
      (el) => (el.textContent || '').includes(${JSON.stringify(options.visibilityLabel)})
    );
    if (!(visibility instanceof HTMLElement)) return false;
    visibility.click();
    return true;
  }`));
    if (!visibilityOk) {
        throw new CommandExecutionError('填写抖音草稿表单失败: visibility-missing');
    }
}
/**
 * Switch the composer into custom-cover mode and expose the cover input with a
 * stable selector for CDP file injection.
 */
async function prepareCustomCoverInput(page) {
    let lastReason = 'cover-input-missing';
    const baselineCount = (await page.evaluate(`() => Array.from(document.querySelectorAll('input[type="file"]')).length`));
    for (let attempt = 0; attempt < COVER_INPUT_WAIT_ATTEMPTS; attempt += 1) {
        const result = (await page.evaluate(`() => {
      const coverLabel = Array.from(document.querySelectorAll('label')).find(
        (el) => (el.textContent || '').includes('上传新封面')
      );
      if (coverLabel instanceof HTMLElement) {
        coverLabel.click();
      }

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry once in case the section rendered late
  2. Inspect the composer page and update the visibility label text mapping (VISIBILITY_LABELS in clis/douyin/draft.js:12) or switch from 'label' to a broader selector like '[role="radio"]'
  3. Use the default --visibility public which matches the most stable '公开' label

Example fix

// before
const visibility = Array.from(document.querySelectorAll('label')).find(
  (el) => (el.textContent || '').includes('好友可见')
);
// after: broader match
const visibility = Array.from(document.querySelectorAll('label,[role="radio"]')).find(
  (el) => /好友可见|好友圈/.test(el.textContent || '')
);
Defensive patterns

Strategy: try-catch

Try / catch

try {
  await opencli.douyin.draft({ video, title, visibility: 'friends' });
} catch (e) {
  if (e.message.includes('visibility-missing')) {
    // retry with default visibility 'public'
    await opencli.douyin.draft({ video, title, visibility: 'public' });
  }
}

Prevention

When it happens

Trigger: Douyin composer renders visibility options as radio buttons/custom components without a <label> containing the expected Chinese text; the visibility section is collapsed or virtualized away; the '好友可见' label copy changed (e.g. to '好友圈').

Common situations: Douyin UI update renaming visibility options; new accounts with different default visibility UI; label rendered only after scrolling the page.

Related errors


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