{"record":{"id":"6d5d013a559e1850","repo":"xpzouying/xiaohongshu-mcp","slug":"s-6d5d01","errorCode":null,"errorMessage":"未找到评论 %s，它可能不在「评论和@」里或已被清理","messagePattern":"未找到评论 (.+?)，它可能不在「评论和@」里或已被清理","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/notification_reply.go","lineNumber":123,"sourceCode":"\n\tfor range maxRounds {\n\t\tpayload, err := n.readTab(page, TabMentions)\n\t\tif err != nil {\n\t\t\treturn nil, 0, err\n\t\t}\n\n\t\tfor i, r := range payload.MessageList {\n\t\t\tif r.Comment.ID != commentID {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif !r.visible() {\n\t\t\t\treturn nil, 0, fmt.Errorf(\"该评论已删除或不可见，不能回复: %s\", commentID)\n\t\t\t}\n\t\t\treturn &r, i, nil\n\t\t}\n\n\t\tif !payload.HasMore {\n\t\t\treturn nil, 0, fmt.Errorf(\"未找到评论 %s，它可能不在「评论和@」里或已被清理\", commentID)\n\t\t}\n\n\t\tif err := page.Mouse.Scroll(0, 800, 5); err != nil {\n\t\t\treturn nil, 0, fmt.Errorf(\"滚动查找失败: %w\", err)\n\t\t}\n\t\thumanize.Delay(ctx, humanize.BetweenScroll)\n\n\t\tif err := ctx.Err(); err != nil {\n\t\t\treturn nil, 0, err\n\t\t}\n\t}\n\treturn nil, 0, fmt.Errorf(\"翻找 %d 轮仍未定位到评论 %s\", maxRounds, commentID)\n}\n\n// verifyReplyTarget 用输入框的 placeholder 核对回复对象。\nfunc verifyReplyTarget(input *rod.Element, nickname string) error {\n\tplaceholder, err := input.Attribute(\"placeholder\")\n\tif err != nil || placeholder == nil {","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/notification_reply.go#L105-L141","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the commentID is a real comment ID from a NotificationItem.Comment.ID, not a feed or note ID","Refresh the notification list (re-fetch notifications) and confirm the comment still appears in「评论和@」before replying","If the comment is known only from a note page, use the note-page reply flow instead of the notification-reply flow","Handle the error by marking the comment as no-longer-replyable in your data store and skip it"],"exampleFix":"// before\n_, err := action.Reply(ctx, staleCommentID, \"thanks\")\n// after\nitems, _ := action.List(ctx, TabMentions) // or readTab equivalent\nfound := false\nfor _, it := range items { if it.Comment.ID == staleCommentID { found = true } }\nif !found { log.Printf(\"skip: comment %s no longer in mentions\", staleCommentID); return nil }","handlingStrategy":"validation","validationCode":"// refresh the mentions list and confirm the comment is present before replying\npayload, err := readTabMentions() // your own refresh of the notification list\nif err != nil { return err }\nfound := false\nfor _, m := range payload.MessageList {\n    if m.Comment.ID == commentID && m.visible() { found = true; break }\n}\nif !found { return fmt.Errorf(\"comment %s not currently in mentions; skip reply\", commentID) }","typeGuard":"func isReplyable(m NotificationMessage) bool {\n    return m.Comment.ID != \"\" && m.visible()\n}","tryCatchPattern":null,"preventionTips":["Store comment IDs together with a timestamp and refuse to reply to comments older than a few days","Always re-fetch the notification list before replying instead of trusting cached IDs","Distinguish comment IDs from feed/note IDs at ingestion time","Treat this error as permanent for that ID — do not retry the same commentID"],"tags":["browser-automation","go","xiaohongshu","element-not-found"],"backgroundTag":"comment-not-found","analyzedSha":"332d196854a9eac0d2b8c2c0e3d0cc43139d724c","analyzedAt":"2026-09-05T22:22:55.988Z","contentChangedAt":"2026-09-05T22:22:55.988Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}