{"record":{"id":"a8d18930134ae643","repo":"xpzouying/xiaohongshu-mcp","slug":"no-textbox-parent-found","errorCode":null,"errorMessage":"no textbox parent found","messagePattern":"no textbox parent found","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish.go","lineNumber":774,"sourceCode":"}\n\nfunc findTextboxByPlaceholder(page *rod.Page) (*rod.Element, error) {\n\telements, err := page.Elements(\"p\")\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"查找正文候选元素失败\")\n\t}\n\tif len(elements) == 0 {\n\t\treturn nil, errors.New(\"no p elements found\")\n\t}\n\n\tplaceholderElem := findPlaceholderElement(elements, \"输入正文描述\")\n\tif placeholderElem == nil {\n\t\treturn nil, errors.New(\"no placeholder element found\")\n\t}\n\n\ttextboxElem := findTextboxParent(placeholderElem)\n\tif textboxElem == nil {\n\t\treturn nil, errors.New(\"no textbox parent found\")\n\t}\n\n\treturn textboxElem, nil\n}\n\nfunc findPlaceholderElement(elements []*rod.Element, searchText string) *rod.Element {\n\tfor _, elem := range elements {\n\t\tplaceholder, err := elem.Attribute(\"data-placeholder\")\n\t\tif err != nil || placeholder == nil {\n\t\t\tcontinue\n\t\t}\n\n\t\tif strings.Contains(*placeholder, searchText) && isElementVisible(elem) {\n\t\t\treturn elem\n\t\t}\n\t}\n\treturn nil\n}","sourceCodeStart":756,"sourceCodeEnd":792,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish.go#L756-L792","documentation":"Once the placeholder <p> is located, findTextboxByPlaceholder climbs ancestors via findTextboxParent to find the actual editable container ([contenteditable] or equivalent). If no ancestor qualifies, it throws 'no textbox parent found'. The placeholder text node exists but its editable wrapper isn't recognized by the current ancestor checks — typically due to an XHS editor DOM restructure.","triggerScenarios":"findContentElement → findTextboxByPlaceholder; placeholder <p> found but findTextboxParent never encounters a [contenteditable]/editable ancestor within its traversal depth because XHS wrapped the editor in new elements or moved contenteditable to a shadow/iframe boundary.","commonSituations":"XHS editor upgrade changing nesting depth or moving contenteditable off the ancestor chain; placeholder rendered inside a tooltip/overlay layer rather than the editor itself; proxy/injected wrapper elements altering ancestry.","solutions":["Inspect the current editor DOM and extend findTextboxParent's matching rules (e.g. also accept elements with class like 'ql-editor' or role=textbox)","Increase traversal depth if the contenteditable ancestor is higher than the current limit","Verify the placeholder <p> you matched is inside the real editor, not a template/hidden copy","If matching stays brittle, locate the editor directly via a stable wrapper selector instead of climbing from the placeholder"],"exampleFix":"// before\ntextboxElem := findTextboxParent(placeholderElem)\n// after\ntextboxElem := findTextboxParent(placeholderElem)\nif textboxElem == nil {\n\t// 兜底：直接按编辑器容器选择器找\n\tif el, err := page.Element(\"[contenteditable='true']\"); err == nil {\n\t\ttextboxElem = el\n\t}\n}","handlingStrategy":"fallback","validationCode":"// 直接探测编辑器容器是否可定位\nif _, err := page.Element(\"[contenteditable='true'], .ql-editor\"); err != nil {\n\treturn errors.New(\"未找到可编辑正文容器\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer locating the editor by a stable wrapper selector over ancestor-climbing from the placeholder","Re-check findTextboxParent's accepted patterns after XHS editor upgrades","Verify the matched placeholder <p> is inside the real editor, not a hidden template"],"tags":["dom","contenteditable","selector-drift","xiaohongshu"],"backgroundTag":"editable-parent-not-found","analyzedSha":"332d196854a9eac0d2b8c2c0e3d0cc43139d724c","analyzedAt":"2026-09-05T22:22:55.988Z","contentChangedAt":"2026-09-05T22:22:55.988Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}