jackwener/OpenCLI · error · CommandExecutionError

Could not attach topic "${topic}": body editor not found

Error message

Could not attach topic "${topic}": body editor not found

What it means

CommandExecutionError from addTopics: before attaching a topic the code calls focusBodyEnd to place the caret at the end of the note body editor; if it cannot find/focus the editor it aborts rather than typing '#' into the void. Thrown per-topic at the start of each topic iteration.

Source

Thrown at clis/xiaohongshu/publish.js:576

        catch {
            // fall through to execCommand path
        }
    }
    return unwrapBrowserResult(await page.evaluate(`
    (text => {
      const ok = document.execCommand('insertText', false, text);
      const active = document.activeElement;
      if (active) active.dispatchEvent(new Event('input', { bubbles: true }));
      return ok;
    })(${JSON.stringify(query)})
  `));
}
async function addTopics(page, bodySelectors, topics) {
    const added = [];
    for (const topic of topics) {
        const focused = await focusBodyEnd(page, bodySelectors);
        if (!focused) {
            throw new CommandExecutionError(`Could not attach topic "${topic}": body editor not found`);
        }
        const beforeMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;
        // Separate this topic from the preceding text so the dropdown is clean.
        if (typeof page.pressKey === 'function') {
            try {
                await page.pressKey('Enter');
            }
            catch { /* non-fatal */ }
        }
        // Type the inline "#<topic>" query so XHS pops the inline suggestion
        // dropdown. We must use `page.insertText` (CDP) rather than the legacy
        // `execCommand` path, otherwise XHS's editor doesn't fire its keyup
        // listener and no dropdown appears.
        if (typeof page.insertText !== 'function') {
            throw new CommandExecutionError(`Could not attach topic "${topic}": page.insertText is unavailable`);
        }
        try {
            await page.insertText(`#${topic}`);

View on GitHub (pinned to 49907e53dc)

Solutions

  1. Verify the session is logged in and the publish page shows the body editor.
  2. Add delays/waits so the editor fully renders before topics are attached.
  3. Update the CLI to get refreshed body selectors.
  4. Use the debug screenshots from earlier fill failures to identify page-state problems.

Example fix

// before
await xhs.publish({ topics: ['travel'], images: [...] });
// after
await xhs.publish({ topics: ['travel'], images: [...], wait: 8 }); // give editor time to mount
// or wrap: try { ... } catch (e) { if (e.message.includes('body editor not found')) retryAfterDelay(); }
Defensive patterns

Strategy: retry

Validate before calling

// ensure logged-in publisher page loads before topic attach
if ((await page.url()).includes('login')) throw new Error('session expired');

Try / catch

try {
  await xhs.publish(opts);
} catch (err) {
  if (err.message.includes('body editor not found')) {
    await sleep(8000); // let editor mount
    return retryPublish(opts);
  }
  throw err;
}

Prevention

When it happens

Trigger: Body editor selector list no longer matches the XHS editor DOM; editor not yet mounted when addTopics runs; page navigated or showing a login/verification wall; editor inside a shadow root the focus logic cannot reach after an update.

Common situations: XHS redesign of the creator editor; publishing without a valid session so the editor never renders; timing issues on slow machines/networks.

Related errors


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