{"record":{"id":"63a0c6589479bc34","repo":"xpzouying/xiaohongshu-mcp","slug":"comment-id","errorCode":null,"errorMessage":"缺少 comment_id","messagePattern":"缺少 comment_id","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/notification_like.go","lineNumber":29,"sourceCode":"\t\"github.com/xpzouying/xiaohongshu-mcp/humanize\"\n)\n\n// NotificationLikeResult 通知点赞的结果。\ntype NotificationLikeResult struct {\n\tCommentID string `json:\"comment_id\"`\n\tNickname  string `json:\"nickname\"`\n\tLiked     bool   `json:\"liked\"`\n\t// Skipped 表示调用前已是目标状态，本次未操作。\n\tSkipped bool `json:\"skipped\"`\n}\n\n// likeSettleTimeout 是等待点赞状态生效的上限。\nconst likeSettleTimeout = 15 * time.Second\n\n// Like 给一条评论点赞或取消点赞；已是目标状态时直接返回。\nfunc (n *NotificationAction) Like(ctx context.Context, commentID string, unlike bool) (*NotificationLikeResult, error) {\n\tif strings.TrimSpace(commentID) == \"\" {\n\t\treturn nil, fmt.Errorf(\"缺少 comment_id\")\n\t}\n\n\twant := !unlike\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\tresult := &NotificationLikeResult{\n\t\tCommentID: commentID,\n\t\tNickname:  target.from().Nickname,\n\t\tLiked:     want,\n\t}","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/notification_like.go#L11-L47","documentation":"Like 方法的参数校验守卫：commentID trim 后为空字符串，调用方未提供要点赞的评论 ID，属必填参数缺失，非页面操作故障。","triggerScenarios":"调用 Like(ctx, \"\", unlike) 或传入只含空格的 commentID。","commonSituations":"上游 list_notifications 结果未做判空就透传；JSON 反序列化时字段缺失得到空串；字符串裁剪后忘记重新赋值。","solutions":["调用前用 strings.TrimSpace 校验 commentID 非空","从 List 结果中复制 commentID 时确认字段确实有值","在调用方对空值提前返回，不进入自动化流程"],"exampleFix":"// before\nn.Like(ctx, commentID, false) // commentID 可能为 \"\"\n// after\nif strings.TrimSpace(commentID) == \"\" { return errors.New(\"comment_id required\") }\nn.Like(ctx, strings.TrimSpace(commentID), false)","handlingStrategy":"validation","validationCode":"func validCommentID(id string) bool { return strings.TrimSpace(id) != \"\" }\nif !validCommentID(commentID) { return errors.New(\"comment_id 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.Like(ctx, commentID, false); err != nil && strings.Contains(err.Error(), \"缺少 comment_id\") {\n    return fmt.Errorf(\"caller bug: empty comment_id: %w\", err)\n}","preventionTips":["封装统一参数校验函数，所有 action 调用前先过校验","从 JSON 反序列化后立即检查关键字段非空","对上游数据做白名单/必填字段检查"],"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-14T00:17:10.932Z"}