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 nilView on GitHub (pinned to 332d196854)
Solutions
- Scroll the element into view before clicking (e.g. rod's el.MustScrollIntoView() or a JS scrollIntoView call)
- 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
- Update the viewport (page.SetViewport) or resize the window to cover the target point
- Re-read the element position immediately before clicking to avoid stale coordinates
- 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
- Always scroll the element into view before computing/clicking points
- Re-read element positions immediately before clicking; never cache across layout changes
- Set an explicit viewport size (page.SetViewport) instead of relying on defaults
- Account for device pixel ratio / zoom when converting coordinates
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.