{"record":{"id":"5b07663f9f6c686e","repo":"xpzouying/xiaohongshu-mcp","slug":"error-5b0766","errorCode":null,"errorMessage":"回复内容不能为空","messagePattern":"回复内容不能为空","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"xiaohongshu/notification_reply.go","lineNumber":28,"sourceCode":"\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)\n\t}\n\tif index >= len(items) {\n\t\treturn nil, fmt.Errorf(\"通知条目渲染数(%d)少于目标位置(%d)，页面可能未加载完\", len(items), index)","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/notification_reply.go#L10-L46","documentation":"Reply validates its inputs before opening the browser and fails fast when the reply body is empty or whitespace-only. Xiaohongshu rejects empty replies, so the library checks strings.TrimSpace(content) and returns this error to avoid a wasted page navigation. It is thrown before any network or browser interaction.","triggerScenarios":"Calling NotificationAction.Reply(ctx, commentID, \"\") or with content consisting only of spaces/tabs/newlines (e.g. a variable that failed to populate upstream).","commonSituations":"Template/LLM-generated reply text came back empty; config or DB lookup returned blank string; caller trimmed content and passed the result accidentally.","solutions":["Pass a non-empty, trimmed reply string to Reply","Validate content at the call site before invoking Reply","Log the content variable upstream to find where it became empty"],"exampleFix":"// before\ncontent := tpl.Execute(data)\nreply, err := n.Reply(ctx, commentID, content)\n// after\ncontent := strings.TrimSpace(tpl.Execute(data))\nif content == \"\" {\n    return fmt.Errorf(\"reply template produced empty content\")\n}\nreply, err := n.Reply(ctx, commentID, content)","handlingStrategy":"validation","validationCode":"if strings.TrimSpace(commentID) == \"\" || strings.TrimSpace(content) == \"\" {\n    return fmt.Errorf(\"commentID and content must be non-empty\")\n}","typeGuard":null,"tryCatchPattern":"res, err := n.Reply(ctx, commentID, content)\nif err != nil && strings.Contains(err.Error(), \"回复内容不能为空\") {\n    // fix input upstream, do not retry\n}","preventionTips":["Trim and check content before every Reply call","Validate LLM/template output is non-empty before passing it in","Fail fast at the call site with a clear message"],"tags":["validation","input","xiaohongshu"],"backgroundTag":"empty-required-field","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"}