xpzouying/xiaohongshu-mcp · error

未找到评论 %s,它可能不在「评论和@」里或已被清理

Error message

未找到评论 %s,它可能不在「评论和@」里或已被清理

What it means

locate() walks the「评论和@」(mentions) notification tab, matching payload.MessageList entries by comment ID. It scrolls and pages through the list; when the API reports HasMore=false without ever matching the requested commentID, it concludes the comment is not reachable via that tab and returns this error. This is a deliberate, user-facing message — not an internal failure.

Source

Thrown at xiaohongshu/notification_reply.go:123

	for range maxRounds {
		payload, err := n.readTab(page, TabMentions)
		if err != nil {
			return nil, 0, err
		}

		for i, r := range payload.MessageList {
			if r.Comment.ID != commentID {
				continue
			}
			if !r.visible() {
				return nil, 0, fmt.Errorf("该评论已删除或不可见,不能回复: %s", commentID)
			}
			return &r, i, nil
		}

		if !payload.HasMore {
			return nil, 0, fmt.Errorf("未找到评论 %s,它可能不在「评论和@」里或已被清理", commentID)
		}

		if err := page.Mouse.Scroll(0, 800, 5); err != nil {
			return nil, 0, fmt.Errorf("滚动查找失败: %w", err)
		}
		humanize.Delay(ctx, humanize.BetweenScroll)

		if err := ctx.Err(); err != nil {
			return nil, 0, err
		}
	}
	return nil, 0, fmt.Errorf("翻找 %d 轮仍未定位到评论 %s", maxRounds, commentID)
}

// verifyReplyTarget 用输入框的 placeholder 核对回复对象。
func verifyReplyTarget(input *rod.Element, nickname string) error {
	placeholder, err := input.Attribute("placeholder")
	if err != nil || placeholder == nil {

View on GitHub (pinned to 332d196854)

Solutions

  1. Verify the commentID is a real comment ID from a NotificationItem.Comment.ID, not a feed or note ID
  2. Refresh the notification list (re-fetch notifications) and confirm the comment still appears in「评论和@」before replying
  3. If the comment is known only from a note page, use the note-page reply flow instead of the notification-reply flow
  4. Handle the error by marking the comment as no-longer-replyable in your data store and skip it

Example fix

// before
_, err := action.Reply(ctx, staleCommentID, "thanks")
// after
items, _ := action.List(ctx, TabMentions) // or readTab equivalent
found := false
for _, it := range items { if it.Comment.ID == staleCommentID { found = true } }
if !found { log.Printf("skip: comment %s no longer in mentions", staleCommentID); return nil }
Defensive patterns

Strategy: validation

Validate before calling

// refresh the mentions list and confirm the comment is present before replying
payload, err := readTabMentions() // your own refresh of the notification list
if err != nil { return err }
found := false
for _, m := range payload.MessageList {
    if m.Comment.ID == commentID && m.visible() { found = true; break }
}
if !found { return fmt.Errorf("comment %s not currently in mentions; skip reply", commentID) }

Type guard

func isReplyable(m NotificationMessage) bool {
    return m.Comment.ID != "" && m.visible()
}

Prevention

When it happens

Trigger: Calling NotificationAction.Reply(ctx, commentID, content) (or Like) with a commentID that: (1) never appeared in「评论和@」notifications (e.g. it came from a different feed), (2) was auto-cleaned/expired by the platform's notification retention, (3) is deleted (this error is the fallback after the deleted-check passes the visible list), or (4) sits beyond 20 scroll rounds while HasMore remains true then flips false before it is reached.

Common situations: Reusing a stale commentID stored from a previous session; replying to a comment whose notification XHS already pruned; passing a feed/note ID instead of a comment ID; the notification list ordering changed so the comment falls off before HasMore becomes false.

Related errors


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