{"record":{"id":"d3efb09ca9188b48","repo":"xpzouying/xiaohongshu-mcp","slug":"comment-id-d3efb0","errorCode":null,"errorMessage":"缺少 comment_id","messagePattern":"缺少 comment_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/notification_reply.go","lineNumber":25,"sourceCode":"\t\"time\"\n\n\t\"github.com/go-rod/rod\"\n\t\"github.com/sirupsen/logrus\"\n\t\"github.com/xpzouying/xiaohongshu-mcp/humanize\"\n)\n\n// NotificationReplyResult 通知回复的结果。\ntype NotificationReplyResult struct {\n\tCommentID string `json:\"comment_id\"`\n\tNickname  string `json:\"nickname\"`\n\tFeedID    string `json:\"feed_id,omitempty\"`\n\tContent   string `json:\"content\"`\n}\n\n// Reply 回复一条评论。\nfunc (n *NotificationAction) Reply(ctx context.Context, commentID, content string) (*NotificationReplyResult, error) {\n\tif strings.TrimSpace(commentID) == \"\" {\n\t\treturn nil, fmt.Errorf(\"缺少 comment_id\")\n\t}\n\tif strings.TrimSpace(content) == \"\" {\n\t\treturn nil, fmt.Errorf(\"回复内容不能为空\")\n\t}\n\n\tpage := n.page.Timeout(3 * time.Minute)\n\n\tpage.MustNavigate(\"https://www.xiaohongshu.com/notification\").MustWaitLoad()\n\thumanize.Delay(ctx, humanize.AfterNavigate)\n\n\ttarget, index, err := n.locate(ctx, page, commentID)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\titems, err := page.Elements(`.tabs-content-container > .container`)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"未找到通知条目: %w\", err)","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/notification_reply.go#L7-L43","documentation":"Reply 方法的参数校验守卫：commentID trim 后为空字符串，调用方未提供要回复的评论 ID，属必填参数缺失。","triggerScenarios":"调用 Reply(ctx, \"\", content) 或传入只含空格的 commentID。","commonSituations":"上游通知列表数据字段缺失透传；JSON 解码得到空串；调用方拼接 commentID 时模板变量为空。","solutions":["调用前用 strings.TrimSpace 校验 commentID 非空","同时校验 content 非空（库同样会拒绝空内容）","在调用方对空值提前返回，不进入自动化流程"],"exampleFix":"// before\nn.Reply(ctx, commentID, content) // commentID 可能为 \"\"\n// after\nif strings.TrimSpace(commentID) == \"\" { return errors.New(\"comment_id required\") }\nn.Reply(ctx, strings.TrimSpace(commentID), content)","handlingStrategy":"validation","validationCode":"func validReplyParams(id, content string) bool {\n    return strings.TrimSpace(id) != \"\" && strings.TrimSpace(content) != \"\"\n}\nif !validReplyParams(commentID, content) { return errors.New(\"comment_id and content required\") }","typeGuard":"func hasCommentID(raw map[string]string) (string, bool) {\n    id, ok := raw[\"comment_id\"]\n    return id, ok && strings.TrimSpace(id) != \"\"\n}","tryCatchPattern":"if _, err := n.Reply(ctx, commentID, content); err != nil && strings.Contains(err.Error(), \"缺少 comment_id\") {\n    return fmt.Errorf(\"caller bug: empty comment_id: %w\", err)\n}","preventionTips":["所有 action 调用前统一做必填参数校验","JSON 解码后立即检查 comment_id/content 非空","模板变量拼接 ID 时检查变量已赋值"],"tags":["go","validation","input-validation"],"backgroundTag":"missing-required-parameter","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"}