{"record":{"id":"4b6add3eb8f20105","repo":"jackwener/OpenCLI","slug":"could-not-attach-topic-topic-no-real-topic-e","errorCode":null,"errorMessage":"Could not attach topic \"${topic}\": no real topic entity appeared after selection","messagePattern":"Could not attach topic \"(.+?)\": no real topic entity appeared after selection","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/xiaohongshu/publish.js","lineNumber":623,"sourceCode":"        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) {\n    const result = await page.evaluate(`\n    () => {\n      const isVisible = (el) => {\n        if (!el || el.offsetParent === null) return false;\n        const rect = el.getBoundingClientRect();\n        return rect.width > 0 && rect.height > 0;\n      };\n\n      const normalize = (value) => (value || '').replace(/\\\\s+/g, ' ').trim();\n      const selector = 'button, [role=\"tab\"], [role=\"button\"], a, label, div, span, li';\n      const nodes = Array.from(document.querySelectorAll(selector));","sourceCodeStart":605,"sourceCodeEnd":641,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/xiaohongshu/publish.js#L605-L641","documentation":"After pressing Enter on a topic suggestion, addTopics verifies the postcondition by counting a \"#<topic>[话题]\" marker inside the body editor's innerText. If the marker count did not increase, the topic chip/entity was not really created, so it throws instead of reporting a topic as added that isn't.","triggerScenarios":"The Enter keypress was sent but XHS did not render a real topic entity: suggestion dropdown had no matching topic, the wrong suggestion was highlighted, or the marker script ran before the chip rendered (count unchanged vs beforeMarkerCount).","commonSituations":"Topic string with no existing XHS topic (no suggestion appears); typing raced the dropdown; network lag so chip renders after the 0.8s wait; body selector list (bodySelectors) does not match current XHS DOM after a site update.","solutions":["Verify the topic exists on XHS (search it in the XHS app/web); topics must match a real topic entity.","Increase wait time before verification or retry addTopics so the chip has time to render.","Try the topic in the XHS UI manually; if XHS changed its DOM, update bodySelectors / topicMarkerCountScript.","Drop the topic from the list or use a close-match topic that XHS suggests."],"exampleFix":"// before\nawait addTopics(page, [\"完全自造的话题\"]);\n// after\nconst valid = topics.filter(t => topicLikelyExists(t)); // only real XHS topics\nawait addTopics(page, valid);","handlingStrategy":"validation","validationCode":"const known = new Set(['旅行','美食','摄影']); // topics verified to exist on XHS\nconst bad = topics.filter(t => !known.has(t));\nif (bad.length) console.warn('Topics may not exist on XHS:', bad);","typeGuard":"null","tryCatchPattern":"try { await addTopics(page, topics); }\ncatch (e) {\n  if (/no real topic entity appeared/.test(e.message)) {\n    console.warn(`Skipping topic that failed to attach`); // degrade gracefully\n  } else throw e;\n}","preventionTips":["Only pass topics that exist on XHS (verified manually or from XHS's topic API)","Avoid very new/niche topics with no suggestion entry","Add small delays between typing and accepting suggestions"],"tags":["xhs-dom","ui-verification","postcondition-failed"],"backgroundTag":"ui-postcondition-not-met","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}