jackwener/OpenCLI · error · CommandExecutionError

Could not attach topic

Error message

Could not attach topic "${topic}": failed to accept suggestion (${err && err.message || err})

What it means

addTopics types a '#' topic then presses Enter to accept XHS's topic suggestion dropdown. If the Enter keypress fails (browser API throws), the library wraps the underlying error in a CommandExecutionError so the topic attach step fails loudly instead of silently skipping the topic.

Solutions

  1. Check the inner err.message for the root cause (connection lost vs rejected key) and restore/reconnect the browser session, then retry publishing.
  2. Ensure the topic suggestion popup is actually open before Enter is pressed: slower typing / wait for the dropdown before calling addTopics.
  3. Retry the publish run; XHS UI timing is flaky and Enter acceptance often succeeds on a second attempt.
  4. If pressKey is systematically unavailable, verify the page wrapper implements pressKey (the code checks for its absence earlier at the 'pressKey is unavailable' branch).

Example fix

// before
await addTopics(page, topics); // throws on popup timing race
// after
for (const topic of topics) {
  try {
    await page.wait({ time: 1.0 });
    await addTopics(page, [topic]);
  } catch (e) {
    if (!/failed to accept suggestion/.test(e.message)) throw e;
    // retry once
    await page.wait({ time: 2.0 });
    await addTopics(page, [topic]);
  }
}
Defensive patterns

Strategy: retry

Validate before calling

if (typeof page.pressKey !== 'function') throw new Error('page.pressKey unavailable; cannot attach topics');

Type guard

function canPress(page) { return typeof page.pressKey === 'function'; }

Try / catch

try { await addTopics(page, topics); }
catch (e) {
  if (/failed to accept suggestion/.test(e.message)) {
    await page.wait({ time: 2.0 });
    await addTopics(page, topics); // retry once
  } else throw e;
}

Prevention

When it happens

Trigger: page.pressKey('Enter') throws while a topic suggestion popup is open after typing "#<topic>" in the publish editor, e.g. browser connection dropped, page navigated, or the browser driver rejected the key event.

Common situations: Browser session crashed or disconnected mid-flow; suggestion popup stole focus or closed before Enter landed; remote browser (CDP/webdriver) rate-limits or errors on key events; running in a headless driver whose pressKey implementation is missing or throws.

Related errors


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

Appendix: source

Thrown at clis/xiaohongshu/publish.js:612

            await page.insertText(`#${topic}`);
        }
        catch {
            throw new CommandExecutionError(`Could not attach topic "${topic}": failed to type inline topic query`);
        }
        await page.wait({ time: 1.2 }); // Let the suggestion dropdown render.
        // The suggestion dropdown lives inside the editor's closed shadow root,
        // so light-DOM queries cannot enumerate its items. XHS auto-highlights
        // the first matching suggestion as soon as the query is typed, so
        // pressing Enter accepts it directly. `page.nativeClick` would also
        // work but is not always wired up in the browser-bridge wrapper.
        if (typeof page.pressKey !== 'function') {
            throw new CommandExecutionError(`Could not attach topic "${topic}": page.pressKey is unavailable`);
        }
        try {
            await page.pressKey('Enter');
        }
        catch (err) {
            throw new CommandExecutionError(`Could not attach topic "${topic}": failed to accept suggestion (${err && err.message || err})`);
        }
        await page.wait({ time: 0.8 });
        // Verify the topic chip actually rendered. The chip itself lives in a
        // closed shadow root so we cannot count `<a>` elements, but XHS exposes
        // a stable "#<topic>[话题]" marker in the body editor's innerText once
        // the suggestion is accepted. Require the scoped marker count to
        // increase so an existing marker elsewhere cannot satisfy the write
        // postcondition.
        const afterMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;
        if (afterMarkerCount <= beforeMarkerCount) {
            throw new CommandExecutionError(`Could not attach topic "${topic}": no real topic entity appeared after selection`);
        }
        added.push(topic);
        await page.wait({ time: 0.4 });
    }
    return added;
}
async function selectImageTextTab(page) {

View on GitHub (pinned to 49907e53dc)