xpzouying/xiaohongshu-mcp · error

落点 (%.0f,%.0f) 在视口 %.0fx%.0f 之外

Error message

落点 (%.0f,%.0f) 在视口 %.0fx%.0f 之外

What it means

ensurePointInViewport reads the viewport size (evaluated via JS into a []float64 of [width, height]) and rejects click coordinates that fall outside it. This error means the humanized click point computed for an element lies beyond the visible viewport, so the click would land on nothing.

Source

Thrown at humanize/input.go:58

	if err != nil || len(shape.Quads) == 0 {
		return pt
	}
	return jitterInQuad(pt, shape.Quads[0])
}

func ensurePointInViewport(page *rod.Page, pt proto.Point) error {
	res, err := page.Eval(`() => JSON.stringify([window.innerWidth, window.innerHeight])`)
	if err != nil {
		return err
	}

	var size []float64
	if json.Unmarshal([]byte(res.Value.Str()), &size) != nil || len(size) != 2 {
		return nil
	}

	if pt.X < 0 || pt.Y < 0 || pt.X > size[0] || pt.Y > size[1] {
		return fmt.Errorf("落点 (%.0f,%.0f) 在视口 %.0fx%.0f 之外", pt.X, pt.Y, size[0], size[1])
	}
	return nil
}

// 不用 document.elementFromPoint:结果不稳定
func ensureClickable(elem *rod.Element, pt proto.Point) error {
	if err := ensurePointInViewport(elem.Page(), pt); err != nil {
		return err
	}

	res, err := elem.Eval(`() => getComputedStyle(this).visibility`)
	if err != nil {
		return nil
	}
	if res.Value.Str() == "hidden" {
		return errors.New("元素当前不可命中")
	}
	return nil

View on GitHub (pinned to 332d196854)

Solutions

  1. Scroll the element into view before clicking (e.g. rod's el.MustScrollIntoView() or a JS scrollIntoView call)
  2. Use rod's built-in click helpers that let the browser compute the point (el.MustClick / proto.InputDispatchMouseEvent at the element's box center) instead of manual coordinates
  3. Update the viewport (page.SetViewport) or resize the window to cover the target point
  4. Re-read the element position immediately before clicking to avoid stale coordinates
  5. If the JSON unmarshal of the size fails the check is skipped silently — verify the evaluation returns a proper [w,h] pair

Example fix

// before
page.MustEval("() => window.scrollTo(0, 0)")
el.ClickAt(proto.Point{X: 3000, Y: 4000}) // 落点在视口外
// after
el.MustScrollIntoView()
box := el.MustShape().Box()
el.ClickAt(proto.Point{X: box.X + box.Width/2, Y: box.Y + box.Height/2})
Defensive patterns

Strategy: validation

Validate before calling

// 点击前校验落点
func pointInViewport(pt proto.Point, w, h float64) bool {
	return pt.X >= 0 && pt.Y >= 0 && pt.X <= w && pt.Y <= h
}

Type guard

func validPoint(pt proto.Point, size []float64) bool {
	return len(size) == 2 && pt.X >= 0 && pt.Y >= 0 && pt.X <= size[0] && pt.Y <= size[1]
}

Try / catch

if err := ensurePointInViewport(page, pt); err != nil {
	// 落点在视口外:先滚动元素到可视区,再重新计算坐标
	el.MustScrollIntoView()
	pt = recomputePoint(el)
	if err := ensurePointInViewport(page, pt); err != nil {
		return fmt.Errorf("滚动后落点仍不可用: %w", err)
	}
}

Prevention

When it happens

Trigger: ensureClickable or ClickAt computes proto.Point pt and calls ensurePointInViewport; the point is negative or exceeds the evaluated viewport width/height (pt.X < 0 || pt.Y < 0 || pt.X > size[0] || pt.Y > size[1]).

Common situations: Element is below the fold (y > viewport height) and the code skipped scrolling; the window was resized or the device-scale emulation changed between measuring and clicking; a stale element position cached before a layout shift; clicking an element inside a scrollable inner container whose coordinates exceed the outer viewport; headless run with a small default window size.

Related errors


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