xpzouying/xiaohongshu-mcp · error

no placeholder element found

Error message

no placeholder element found

What it means

After collecting `<p>` elements, findTextboxByPlaceholder scans their text for the placeholder '输入正文描述'. If no p element contains that text it throws 'no placeholder element found'. The description editor either hasn't rendered its placeholder yet, the placeholder text changed, or the user already typed content so the placeholder is gone.

Source

Thrown at xiaohongshu/publish.go:769

		return errors.Wrap(err, "点击标签联想选项失败")
	}
	slog.Info("成功点击标签联想选项", "tag", tag)
	time.Sleep(500 * time.Millisecond) // 技术等待:等标签处理完成
	return nil
}

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) {

View on GitHub (pinned to 332d196854)

Solutions

  1. Inspect the live page's editor DOM and update the placeholder searchText constant to the current copy
  2. Match more loosely (substring or [placeholder]/[data-placeholder] attribute) instead of exact text
  3. Only run this on a fresh publish page — if content was already typed, the placeholder disappears by design
  4. Add the new placeholder text as an additional accepted value rather than replacing it, to tolerate A/B copy

Example fix

// before
placeholderElem := findPlaceholderElement(elements, "输入正文描述")
// after
placeholderElem := findPlaceholderElement(elements, "输入正文描述")
if placeholderElem == nil {
	placeholderElem = findPlaceholderElement(elements, "填写更全面的描述信息") // 新版文案兜底
}
Defensive patterns

Strategy: fallback

Validate before calling

// 填写前确认正文为空(placeholder 只在空内容时存在)
if contentAlreadyFilled(page) {
	return errors.New("正文已填写,无需再定位 placeholder")
}

Prevention

When it happens

Trigger: findContentElement → findTextboxByPlaceholder with searchText='输入正文描述'; the placeholder p exists with different wording (XHS copy update), or content was previously entered (placeholder hidden), or placeholder lives in a different element type (span/div data-placeholder attribute).

Common situations: XHS changing the placeholder copy (e.g. to '填写标题下更全面的描述信息'); re-running the flow on a page where content was already partially filled; locale/variant differences in placeholder text.

Related errors


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