jackwener/OpenCLI · error · CommandExecutionError

准备抖音自定义封面输入框失败: ${lastReason}

Error message

准备抖音自定义封面输入框失败: ${lastReason}

What it means

prepareCustomCoverInput tries up to 20 times (0.5s apart) to click the '上传新封面' label and find a newly-appearing enabled file input, tagging it for CDP file injection. If it never finds one it throws this CommandExecutionError including the last internal reason, typically 'cover-input-missing' or 'cover-input-pending'.

Source

Thrown at clis/douyin/draft.js:158

        .slice(${JSON.stringify(baselineCount)})
        .find((el) => el instanceof HTMLInputElement && !el.disabled);
      if (!(target instanceof HTMLInputElement)) {
        return { ok: false, reason: 'cover-input-pending' };
      }

      document
        .querySelectorAll('[data-opencli-cover-input="1"]')
        .forEach((el) => el.removeAttribute('data-opencli-cover-input'));
      target.setAttribute('data-opencli-cover-input', '1');
      return { ok: true, selector: '[data-opencli-cover-input="1"]' };
    }`));
        if (result?.ok && result.selector) {
            return result.selector;
        }
        lastReason = result?.reason || lastReason;
        await page.wait({ time: 0.5 });
    }
    throw new CommandExecutionError(`准备抖音自定义封面输入框失败: ${lastReason}`);
}
/**
 * Read the local quick-check panel text that reflects cover validation state.
 */
export function buildCoverCheckPanelTextJs() {
    return `() => {
    const normalize = (value) => (value || '').replace(/\\s+/g, ' ').trim();
    const stateTexts = ['检测', '检测中', '封面检测中', '重新检测', '横/竖双封面缺失'];
    const marker = Array.from(document.querySelectorAll('div,span,p,button')).find(
      (el) => normalize(el.textContent) === '快速检测'
    );
    let root = marker?.parentElement || null;
    while (root && root !== document.body) {
      const descendants = Array.from(root.querySelectorAll('div,span,p,button'))
        .map((el) => normalize(el.textContent));
      const hasMarkerText = descendants.includes('快速检测');
      const hasStateText = descendants.some((text) => stateTexts.includes(text));
      if (hasMarkerText && hasStateText) {

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry — if the reason was 'cover-input-pending' the input may just have been slow to enable
  2. Check whether the '上传新封面' label text changed on the live composer and update clis/douyin/draft.js:132
  3. Dismiss any blocking modals first (they are only auto-dismissed before/after composer wait, not during cover prep)
  4. Verify the cover image path is valid (bad path fails later, but a missing panel can stem from a page in a bad state — reload and rerun)

Example fix

// before: fixed label text
const coverLabel = ...find((el) => (el.textContent || '').includes('上传新封面'));
// after: accept variants and increase patience
const coverLabel = ...find((el) => /上传新封面|自定义封面|修改封面/.test(el.textContent || ''));
Defensive patterns

Strategy: retry

Validate before calling

// validate cover input before invoking
const cover = kwargs.cover;
if (cover && !fs.existsSync(path.resolve(cover))) throw new Error('cover missing');

Try / catch

try {
  await opencli.douyin.draft({ video, title, cover });
} catch (e) {
  if (e.message.includes('准备抖音自定义封面输入框失败')) {
    // retry once; if it persists, drop --cover and let Douyin auto-pick a frame
    await opencli.douyin.draft({ video, title });
  }
}

Prevention

When it happens

Trigger: Passing --cover when the custom-cover panel never exposes a usable input[type=file]: the '上传新封面' label is absent (UI change), the input stays disabled, or the file-input count never grows above baselineCount within 10 seconds.

Common situations: Douyin redesigned the cover-edit dialog so the label text changed; cover panel requires a click that lands on a covered element; slow page leaving the input disabled during the whole 10s window; modal (coach mark) blocking the cover entry.

Related errors


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