{"record":{"id":"afc052ecb1bff922","repo":"xpzouying/xiaohongshu-mcp","slug":"error-afc052","errorCode":null,"errorMessage":"小红书发布失败","messagePattern":"小红书发布失败","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish_video.go","lineNumber":68,"sourceCode":"\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) // 视频处理耗时更长\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']\")","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish_video.go#L50-L86","documentation":"PublishVideo wraps any failure from submitPublishVideo with the generic message \"小红书发布失败\". It is a top-level wrapper meaning the video uploaded fine but the form-fill/submit phase (title, content, tags, schedule, visibility, products, publish click, or success check) failed. Check the wrapped cause chain (pkg/errors) for the real step that broke.","triggerScenarios":"Any error returned by submitPublishVideo: DOM element for title/content not found, humanize.Type failing, setSchedulePublish/setVisibility/bindProducts/clickPublishButton errors, or waitPublishSuccess timeout (page did not navigate away within 15s).","commonSituations":"Xiaohongshu changed their publish-page DOM selectors; slow page render caused element lookup timeout; a publish failure dialog appeared so the success navigation never happened; content rejected by platform (sensitive words) keeping the user on the publish page.","solutions":["Read the wrapped cause (errors.Cause / %v of the error) to find the inner step that actually failed","Re-run with a longer context timeout and verify the publish page fully loads before submit","Re-login / refresh cookies — an expired session often leaves the page in a state where form elements never appear","Check if xiaohongshu.com changed publish page markup; update CSS selectors like div.d-input input"],"exampleFix":"// before\nerr := action.PublishVideo(ctx, content)\nlog.Println(err) // 小红书发布失败\n// after\nif err != nil {\n    log.Printf(\"%+v\", err) // print full stack to see the inner cause\n}","handlingStrategy":"try-catch","validationCode":"if content.VideoPath == \"\" { t.Fatal(\"video path required\") }\nif _, err := os.Stat(content.VideoPath); err != nil { t.Fatalf(\"video missing: %v\", err) }\nctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute)\ndefer cancel()","typeGuard":null,"tryCatchPattern":"if err := action.PublishVideo(ctx, content); err != nil {\n    log.Printf(\"publish failed: %+v\", err) // full stack shows the real failing step\n    if strings.Contains(fmt.Sprint(errors.Cause(err)), \"not found\") {\n        // selectors stale — alert for maintenance\n    }\n}","preventionTips":["Always log wrapped errors with %+v to expose the underlying cause","Use a long, never-cancelled context for the whole publish flow","Keep cookies/session fresh before publishing","Smoke-test selectors after any known site update"],"tags":["browser-automation","go","xiaohongshu","error-wrapping"],"backgroundTag":"page-element-not-found","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"}