{"record":{"id":"2fc89d0bc4c21b07","repo":"xpzouying/xiaohongshu-mcp","slug":"error-2fc89d","errorCode":null,"errorMessage":"视频不能为空","messagePattern":"视频不能为空","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish_video.go","lineNumber":57,"sourceCode":"\n\tif err := pp.WaitDOMStable(time.Second, 0.1); err != nil {\n\t\tlogrus.Warnf(\"等待 DOM 稳定出现问题: %v，继续尝试\", err)\n\t}\n\ttime.Sleep(1 * time.Second)\n\n\tif err := mustClickPublishTab(pp, \"上传视频\"); err != nil {\n\t\treturn nil, errors.Wrap(err, \"切换到上传视频失败\")\n\t}\n\n\ttime.Sleep(1 * time.Second)\n\n\treturn &PublishAction{page: pp}, nil\n}\n\n// PublishVideo 上传视频并提交\nfunc (p *PublishAction) PublishVideo(ctx context.Context, content PublishVideoContent) error {\n\tif content.VideoPath == \"\" {\n\t\treturn errors.New(\"视频不能为空\")\n\t}\n\n\t// 重设超时：.Context(ctx) 会替换掉 NewPublishVideoAction 里 Timeout(300s) 的 deadline\n\tpage := p.page.Context(ctx).Timeout(300 * time.Second)\n\n\tif err := uploadVideo(page, content.VideoPath); err != nil {\n\t\treturn errors.Wrap(err, \"小红书上传视频失败\")\n\t}\n\n\tif err := submitPublishVideo(ctx, page, content.Title, content.Content, content.Tags, content.ScheduleTime, content.Visibility, content.Products); err != nil {\n\t\treturn errors.Wrap(err, \"小红书发布失败\")\n\t}\n\treturn nil\n}\n\n// uploadVideo 上传单个本地视频\nfunc uploadVideo(page *rod.Page, videoPath string) error {\n\tpp := page.Timeout(5 * time.Minute) // 视频处理耗时更长","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish_video.go#L39-L75","documentation":"PublishVideo 入口的参数校验守卫：调用方传入的 PublishVideoContent.VideoPath 为空字符串，说明上游构造内容时漏填了视频路径，属于必填项缺失，非运行时故障。","triggerScenarios":"调用 PublishVideo(ctx, PublishVideoContent{...}) 时未设置 VideoPath 字段（漏填、变量名拼错、上层逻辑未给值）。","commonSituations":"从配置文件/命令行读视频路径失败后仍继续调用；结构体零值直接传入；路径校验函数只检查了文件存在性而未检查非空。","solutions":["调用前检查 content.VideoPath != \"\"","确保上层正确读取并传递视频文件路径","同时用 os.Stat 校验文件真实存在"],"exampleFix":"// before\n_ = action.PublishVideo(ctx, PublishVideoContent{Title: title})\n// after\nif videoPath == \"\" { return errors.New(\"video path required\") }\n_ = action.PublishVideo(ctx, PublishVideoContent{VideoPath: videoPath, Title: title})","handlingStrategy":"validation","validationCode":"func validateVideoContent(c PublishVideoContent) error {\n\tif c.VideoPath == \"\" { return errors.New(\"VideoPath 不能为空\") }\n\tif _, err := os.Stat(c.VideoPath); err != nil { return fmt.Errorf(\"视频文件不可读: %w\", err) }\n\treturn nil\n}\n// 调用前: if err := validateVideoContent(content); err != nil { return err }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["构造 PublishVideoContent 后先做非空与文件存在性校验","从配置读取路径时打印日志确认非空","为 VideoPath 提供默认值或启动时校验配置完整性"],"tags":["validation","input","go"],"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"}