{"record":{"id":"91c3532341aa6764","repo":"jackwener/OpenCLI","slug":"could-not-attach-topic-topic-failed-to-accep","errorCode":null,"errorMessage":"Could not attach topic \"${topic}\": failed to accept suggestion (${err && err.message || err})","messagePattern":"Could not attach topic \"(.+?)\": failed to accept suggestion \\((.+?)\\)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/publish.js","lineNumber":612,"sourceCode":"            await page.insertText(`#${topic}`);\n        }\n        catch {\n            throw new CommandExecutionError(`Could not attach topic \"${topic}\": failed to type inline topic query`);\n        }\n        await page.wait({ time: 1.2 }); // Let the suggestion dropdown render.\n        // The suggestion dropdown lives inside the editor's closed shadow root,\n        // so light-DOM queries cannot enumerate its items. XHS auto-highlights\n        // the first matching suggestion as soon as the query is typed, so\n        // pressing Enter accepts it directly. `page.nativeClick` would also\n        // work but is not always wired up in the browser-bridge wrapper.\n        if (typeof page.pressKey !== 'function') {\n            throw new CommandExecutionError(`Could not attach topic \"${topic}\": page.pressKey is unavailable`);\n        }\n        try {\n            await page.pressKey('Enter');\n        }\n        catch (err) {\n            throw new CommandExecutionError(`Could not attach topic \"${topic}\": failed to accept suggestion (${err && err.message || err})`);\n        }\n        await page.wait({ time: 0.8 });\n        // Verify the topic chip actually rendered. The chip itself lives in a\n        // closed shadow root so we cannot count `<a>` elements, but XHS exposes\n        // a stable \"#<topic>[话题]\" marker in the body editor's innerText once\n        // the suggestion is accepted. Require the scoped marker count to\n        // increase so an existing marker elsewhere cannot satisfy the write\n        // postcondition.\n        const afterMarkerCount = Number(unwrapBrowserResult(await page.evaluate(topicMarkerCountScript(topic, bodySelectors)))) || 0;\n        if (afterMarkerCount <= beforeMarkerCount) {\n            throw new CommandExecutionError(`Could not attach topic \"${topic}\": no real topic entity appeared after selection`);\n        }\n        added.push(topic);\n        await page.wait({ time: 0.4 });\n    }\n    return added;\n}\nasync function selectImageTextTab(page) {","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/publish.js#L594-L630","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Check the inner err.message for the root cause (connection lost vs rejected key) and restore/reconnect the browser session, then retry publishing.","Ensure the topic suggestion popup is actually open before Enter is pressed: slower typing / wait for the dropdown before calling addTopics.","Retry the publish run; XHS UI timing is flaky and Enter acceptance often succeeds on a second attempt.","If pressKey is systematically unavailable, verify the page wrapper implements pressKey (the code checks for its absence earlier at the 'pressKey is unavailable' branch)."],"exampleFix":"// before\nawait addTopics(page, topics); // throws on popup timing race\n// after\nfor (const topic of topics) {\n  try {\n    await page.wait({ time: 1.0 });\n    await addTopics(page, [topic]);\n  } catch (e) {\n    if (!/failed to accept suggestion/.test(e.message)) throw e;\n    // retry once\n    await page.wait({ time: 2.0 });\n    await addTopics(page, [topic]);\n  }\n}","handlingStrategy":"retry","validationCode":"if (typeof page.pressKey !== 'function') throw new Error('page.pressKey unavailable; cannot attach topics');","typeGuard":"function canPress(page) { return typeof page.pressKey === 'function'; }","tryCatchPattern":"try { await addTopics(page, topics); }\ncatch (e) {\n  if (/failed to accept suggestion/.test(e.message)) {\n    await page.wait({ time: 2.0 });\n    await addTopics(page, topics); // retry once\n  } else throw e;\n}","preventionTips":["Verify page.pressKey exists before starting the publish flow","Wait for the topic suggestion dropdown before accepting","Keep the browser session alive; check connection before long flows"],"tags":["browser-automation","ui-timing","command-execution-error"],"backgroundTag":"browser-keypress-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}