{"record":{"id":"69f1d6105c41093d","repo":"xpzouying/xiaohongshu-mcp","slug":"s-69f1d6","errorCode":null,"errorMessage":"视频文件不存在: %s","messagePattern":"视频文件不存在: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish_video.go","lineNumber":78,"sourceCode":"\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) // 视频处理耗时更长\n\n\tif _, err := os.Stat(videoPath); os.IsNotExist(err) {\n\t\treturn errors.Wrapf(err, \"视频文件不存在: %s\", videoPath)\n\t}\n\n\t// 寻找文件上传输入框（与图文一致的 class，或退回到 input[type=file]）\n\tvar fileInput *rod.Element\n\tvar err error\n\tfileInput, err = pp.Element(\".upload-input\")\n\tif err != nil || fileInput == nil {\n\t\tfileInput, err = pp.Element(\"input[type='file']\")\n\t\tif err != nil || fileInput == nil {\n\t\t\treturn errors.New(\"未找到视频上传输入框\")\n\t\t}\n\t}\n\n\tfileInput.MustSetFiles(videoPath)\n\n\t// 对于视频，等待发布按钮变为可点击即表示处理完成\n\tbtn, err := waitForPublishButtonClickable(pp, 10*time.Minute)\n\tif err != nil {","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish_video.go#L60-L96","documentation":"uploadVideo checks os.Stat on the provided VideoPath and wraps the os.IsNotExist error with \"视频文件不存在: %s\". The library refuses to start a browser upload for a file that is not on local disk. Note the wrapped err from os.Stat may be nil-typed when os.Stat itself succeeds differently; primarily this fires when the path does not exist.","triggerScenarios":"Calling PublishVideo with content.VideoPath pointing to a file that does not exist at publish time — deleted, moved, wrong relative path relative to the process working directory, or a URL instead of a local path.","commonSituations":"Passing a relative path while the MCP server runs from a different working directory (e.g. Docker container vs host); file cleaned up by a temp-dir purge before publishing; typo in filename; passing a remote URL which os.Stat cannot resolve.","solutions":["Verify the file exists with os.Stat at the exact path before calling PublishVideo","Use an absolute path, or resolve it relative to the process working directory","If running in Docker, mount the video directory into the container and use the container-side path","Check for typos and that the file was not deleted/moved between scheduling and publishing"],"exampleFix":"// before\naction.PublishVideo(ctx, PublishVideoContent{VideoPath: \"clip.mp4\"})\n// after\nabs, err := filepath.Abs(\"clip.mp4\")\nif err != nil { return err }\nif _, err := os.Stat(abs); err != nil { return fmt.Errorf(\"video missing: %w\", err) }\naction.PublishVideo(ctx, PublishVideoContent{VideoPath: abs})","handlingStrategy":"validation","validationCode":"info, err := os.Stat(videoPath)\nif err != nil || info.IsDir() {\n    return fmt.Errorf(\"video not usable at %s: %v\", videoPath, err)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pass absolute paths resolved via filepath.Abs","Stat the file immediately before calling PublishVideo","Mount video directories explicitly when running in containers","Avoid passing URLs — download to a local temp file first"],"tags":["filesystem","go","validation"],"backgroundTag":"file-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"}