xpzouying/xiaohongshu-mcp · error

no textbox parent found

Error message

no textbox parent found

What it means

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.

Source

Thrown at xiaohongshu/publish.go:774

}

func findTextboxByPlaceholder(page *rod.Page) (*rod.Element, error) {
	elements, err := page.Elements("p")
	if err != nil {
		return nil, errors.Wrap(err, "查找正文候选元素失败")
	}
	if len(elements) == 0 {
		return nil, errors.New("no p elements found")
	}

	placeholderElem := findPlaceholderElement(elements, "输入正文描述")
	if placeholderElem == nil {
		return nil, errors.New("no placeholder element found")
	}

	textboxElem := findTextboxParent(placeholderElem)
	if textboxElem == nil {
		return nil, errors.New("no textbox parent found")
	}

	return textboxElem, nil
}

func findPlaceholderElement(elements []*rod.Element, searchText string) *rod.Element {
	for _, elem := range elements {
		placeholder, err := elem.Attribute("data-placeholder")
		if err != nil || placeholder == nil {
			continue
		}

		if strings.Contains(*placeholder, searchText) && isElementVisible(elem) {
			return elem
		}
	}
	return nil
}

View on GitHub (pinned to 332d196854)

Solutions

  1. Inspect the current editor DOM and extend findTextboxParent's matching rules (e.g. also accept elements with class like 'ql-editor' or role=textbox)
  2. Increase traversal depth if the contenteditable ancestor is higher than the current limit
  3. Verify the placeholder <p> you matched is inside the real editor, not a template/hidden copy
  4. If matching stays brittle, locate the editor directly via a stable wrapper selector instead of climbing from the placeholder

Example fix

// before
textboxElem := findTextboxParent(placeholderElem)
// after
textboxElem := findTextboxParent(placeholderElem)
if textboxElem == nil {
	// 兜底:直接按编辑器容器选择器找
	if el, err := page.Element("[contenteditable='true']"); err == nil {
		textboxElem = el
	}
}
Defensive patterns

Strategy: fallback

Validate before calling

// 直接探测编辑器容器是否可定位
if _, err := page.Element("[contenteditable='true'], .ql-editor"); err != nil {
	return errors.New("未找到可编辑正文容器")
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05). Data as JSON: /api/errors/a8d18930134ae643. Report an issue: GitHub.