xpzouying/xiaohongshu-mcp · error

读取旧版发布按钮 class 属性失败

Error message

读取旧版发布按钮 class 属性失败

What it means

findPublishButton wraps the error from Element.Attribute("class") on a visible legacy publish button when the CDP read fails. As with the other attribute reads, this is a transport/element-lifecycle failure, not a 'button has disabled class' result. The library needs the class list to detect the disabled-styled variant, so it aborts the search.

Source

Thrown at xiaohongshu/publish.go:534

	for _, oldButton := range oldButtons {
		if !isElementVisible(oldButton) {
			continue
		}

		if disabled, err := oldButton.Attribute("disabled"); err != nil {
			return nil, "", errors.Wrap(err, "读取旧版发布按钮 disabled 属性失败")
		} else if disabled != nil {
			return &publishButton{elem: oldButton}, "旧版发布按钮 disabled", nil
		}

		if ariaDisabled, err := oldButton.Attribute("aria-disabled"); err != nil {
			return nil, "", errors.Wrap(err, "读取旧版发布按钮 aria-disabled 属性失败")
		} else if ariaDisabled != nil && *ariaDisabled == "true" {
			return &publishButton{elem: oldButton}, "旧版发布按钮 aria-disabled=true", nil
		}

		if cls, err := oldButton.Attribute("class"); err != nil {
			return nil, "", errors.Wrap(err, "读取旧版发布按钮 class 属性失败")
		} else if cls != nil && hasExactClass(*cls, "disabled") {
			return &publishButton{elem: oldButton}, "旧版发布按钮包含 disabled class", nil
		}

		return &publishButton{elem: oldButton}, "", nil
	}

	return nil, "", nil
}

func clickPublishWidget(page *rod.Page, widget *rod.Element) error {
	if err := widget.ScrollIntoView(); err != nil {
		return errors.Wrap(err, "滚动新版发布按钮到可视区域失败")
	}
	time.Sleep(200 * time.Millisecond)

	shape, err := widget.Shape()
	if err != nil {

View on GitHub (pinned to 332d196854)

Solutions

  1. Retry the flow — findPublishButton is invoked inside a polling loop and will pick up fresh elements
  2. Wait for the DOM to settle (page.WaitDOMStable / WaitStable) before starting the publish-button wait
  3. Detect a dead browser/tab and re-launch or re-open the page instead of retrying against the stale handle
  4. Keep rod updated to pick up CDP race-condition fixes

Example fix

// before
for {
    btn, reason, err := findPublishButton(page)
// after
for {
    _ = page.WaitStable(300 * time.Millisecond)
    btn, reason, err := findPublishButton(page)
Defensive patterns

Strategy: retry

Validate before calling

if err := page.WaitStable(300 * time.Millisecond); err != nil { return err }
oldButtons, err := page.Elements(".publish-page-publish-btn button.bg-red")
if err != nil || len(oldButtons) == 0 { return errors.New("旧版发布按钮不可用") }

Type guard

func elementAttached(page *rod.Page, sel string) bool {
    els, err := page.Elements(sel)
    return err == nil && len(els) > 0
}

Try / catch

btn, reason, err := waitForPublishButtonClickable(page)
if err != nil && strings.Contains(err.Error(), "class 属性失败") {
    time.Sleep(500 * time.Millisecond)
    btn, reason, err = waitForPublishButtonClickable(page)
}

Prevention

When it happens

Trigger: Element detached during the attribute-read sequence (after `disabled` and `aria-disabled` reads succeeded); page navigation/closed tab; CDP protocol error; browser OOM crash.

Common situations: Fast re-render of the publish button right as the check runs; flaky connection to a remote Chrome instance; script continuing to use a rod.Page after its window was closed.

Related errors


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