jackwener/OpenCLI · error · CommandExecutionError

文字配图: could not focus card editor #${index + 1}

Error message

文字配图: could not focus card editor #${index + 1}

What it means

fillCard first calls focusActiveCard to place the caret in the Nth 写文字 card editor of the 文字配图 flow. If focusing fails (no active card or the focus attempt reports not-ok), it throws this CommandExecutionError naming the card index.

Source

Thrown at clis/xiaohongshu/publish.js:888

    return false;
}
/**
 * Type one card's text into the active card editor, then verify it stuck.
 *
 * tiptap/ProseMirror swallows a "\n" embedded in a single insertText call, so a
 * multi-line card would collapse onto one line. Split the text on "\n" and press
 * Enter between segments to produce real line breaks (same Enter mechanism
 * addTopics relies on). An empty segment (consecutive "\n") yields a blank line.
 *
 * Single-quoted shell args (the most natural way to pass `--card-text`) deliver a
 * literal backslash + "n", not a real LF, so we normalize those to real newlines
 * first — both `$'a\nb'` and `'a\nb'` then break lines identically.
 */
async function fillCard(page, text, index) {
    text = String(text).replace(/\\n/g, '\n');
    const focused = await focusActiveCard(page);
    if (!focused?.ok)
        throw new CommandExecutionError(`文字配图: could not focus card editor #${index + 1}`);
    if (typeof page.insertText === 'function') {
        const lines = text.split('\n');
        for (let i = 0; i < lines.length; i++) {
            if (i > 0 && typeof page.pressKey === 'function')
                await page.pressKey('Enter');
            if (lines[i])
                await page.insertText(lines[i]);
        }
    }
    else {
        await page.evaluate(`(t => document.execCommand('insertText', false, t))(${JSON.stringify(text)})`);
    }
    await page.wait({ time: 0.4 });
    const state = await activeCardText(page);
    if (!state?.ok)
        throw new CommandExecutionError(`文字配图: card editor #${index + 1} is empty after typing`);
}
/**

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Retry the flow with longer waits after clicking the 文字配图 entry so card editors are mounted.
  2. Reduce the number of cards, or ensure addCard succeeded for card i before fillCard targets it.
  3. Re-run the publish; transient XHS slowness is the most common cause.
  4. If persistent, update focusActiveCard's selectors to match the current XHS DOM.

Example fix

// before
await runTextImageFlow(page, cards, style);
// after
await page.wait({ time: 2.0 }); // let 写文字 editor mount
try {
  await runTextImageFlow(page, cards, style);
} catch (e) {
  if (/could not focus card editor/.test(e.message)) {
    await page.wait({ time: 3.0 });
    await runTextImageFlow(page, cards, style);
  } else throw e;
}
Defensive patterns

Strategy: retry

Validate before calling

// wait until a card editor exists before filling
await page.wait({ time: 2.0 });
if (!(await waitForFirstCard(page))) throw new Error('no card editor mounted');

Type guard

null

Try / catch

try { await fillCard(page, text, i); }
catch (e) {
  if (/could not focus card editor/.test(e.message)) {
    await page.wait({ time: 3.0 });
    await fillCard(page, text, i);
  } else throw e;
}

Prevention

When it happens

Trigger: focusActiveCard returns { ok: false } or null — card editor not rendered yet, wrong card count, editor contenteditable not present, or the click/focus into the editor failed on the 预览/写文字 step.

Common situations: XHS page still loading when runTextImageFlow starts typing cards; a UI update changed card editor selectors; too many cards requested so a later card was never created via addCard; slow network delaying the editor mount.

Related errors


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