{"record":{"id":"22fad131554b9886","repo":"jackwener/OpenCLI","slug":"could-not-focus-card-editor-index-1","errorCode":null,"errorMessage":"文字配图: could not focus card editor #${index + 1}","messagePattern":"文字配图: could not focus card editor #(.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/publish.js","lineNumber":888,"sourceCode":"    return false;\n}\n/**\n * Type one card's text into the active card editor, then verify it stuck.\n *\n * tiptap/ProseMirror swallows a \"\\n\" embedded in a single insertText call, so a\n * multi-line card would collapse onto one line. Split the text on \"\\n\" and press\n * Enter between segments to produce real line breaks (same Enter mechanism\n * addTopics relies on). An empty segment (consecutive \"\\n\") yields a blank line.\n *\n * Single-quoted shell args (the most natural way to pass `--card-text`) deliver a\n * literal backslash + \"n\", not a real LF, so we normalize those to real newlines\n * first — both `$'a\\nb'` and `'a\\nb'` then break lines identically.\n */\nasync function fillCard(page, text, index) {\n    text = String(text).replace(/\\\\n/g, '\\n');\n    const focused = await focusActiveCard(page);\n    if (!focused?.ok)\n        throw new CommandExecutionError(`文字配图: could not focus card editor #${index + 1}`);\n    if (typeof page.insertText === 'function') {\n        const lines = text.split('\\n');\n        for (let i = 0; i < lines.length; i++) {\n            if (i > 0 && typeof page.pressKey === 'function')\n                await page.pressKey('Enter');\n            if (lines[i])\n                await page.insertText(lines[i]);\n        }\n    }\n    else {\n        await page.evaluate(`(t => document.execCommand('insertText', false, t))(${JSON.stringify(text)})`);\n    }\n    await page.wait({ time: 0.4 });\n    const state = await activeCardText(page);\n    if (!state?.ok)\n        throw new CommandExecutionError(`文字配图: card editor #${index + 1} is empty after typing`);\n}\n/**","sourceCodeStart":870,"sourceCodeEnd":906,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/publish.js#L870-L906","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the flow with longer waits after clicking the 文字配图 entry so card editors are mounted.","Reduce the number of cards, or ensure addCard succeeded for card i before fillCard targets it.","Re-run the publish; transient XHS slowness is the most common cause.","If persistent, update focusActiveCard's selectors to match the current XHS DOM."],"exampleFix":"// before\nawait runTextImageFlow(page, cards, style);\n// after\nawait page.wait({ time: 2.0 }); // let 写文字 editor mount\ntry {\n  await runTextImageFlow(page, cards, style);\n} catch (e) {\n  if (/could not focus card editor/.test(e.message)) {\n    await page.wait({ time: 3.0 });\n    await runTextImageFlow(page, cards, style);\n  } else throw e;\n}","handlingStrategy":"retry","validationCode":"// wait until a card editor exists before filling\nawait page.wait({ time: 2.0 });\nif (!(await waitForFirstCard(page))) throw new Error('no card editor mounted');","typeGuard":"null","tryCatchPattern":"try { await fillCard(page, text, i); }\ncatch (e) {\n  if (/could not focus card editor/.test(e.message)) {\n    await page.wait({ time: 3.0 });\n    await fillCard(page, text, i);\n  } else throw e;\n}","preventionTips":["Wait for the 写文字 editor to mount before typing cards","Create each additional card (addCard) before targeting it","Retry transient focus failures once with backoff"],"tags":["browser-automation","focus-failure","ui-timing"],"backgroundTag":"editor-focus-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}