{"record":{"id":"c0616c4aa5daee0f","repo":"xpzouying/xiaohongshu-mcp","slug":"error-c0616c","errorCode":null,"errorMessage":"点击保存按钮失败","messagePattern":"点击保存按钮失败","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish.go","lineNumber":1159,"sourceCode":"\tif err != nil {\n\t\treturn errors.Wrap(err, \"等待商品弹窗失败\")\n\t}\n\tslog.Info(\"商品选择弹窗已打开\")\n\n\t// 遍历搜索并选择商品\n\tvar failedProducts []string\n\tfor _, keyword := range products {\n\t\tif err := searchAndSelectProduct(ctx, page, modal, keyword); err != nil {\n\t\t\tslog.Warn(\"搜索选择商品失败\", \"keyword\", keyword, \"error\", err)\n\t\t\tfailedProducts = append(failedProducts, keyword)\n\t\t}\n\t\ttime.Sleep(500 * time.Millisecond)\n\t}\n\n\t// 点击保存按钮\n\tslog.Info(\"准备点击保存按钮\")\n\tif err := clickModalSaveButton(modal); err != nil {\n\t\treturn errors.Wrap(err, \"点击保存按钮失败\")\n\t}\n\tslog.Info(\"保存按钮点击完成，开始等待弹窗关闭\")\n\n\t// 等待弹窗关闭\n\tif err := waitForModalClose(page); err != nil {\n\t\tslog.Warn(\"等待弹窗关闭超时\", \"error\", err)\n\t} else {\n\t\tslog.Info(\"弹窗已关闭\")\n\t}\n\n\tif len(failedProducts) > 0 {\n\t\treturn errors.Errorf(\"部分商品未找到: %v\", failedProducts)\n\t}\n\n\tslog.Info(\"商品绑定完成\", \"total\", len(products))\n\ttime.Sleep(1000 * time.Millisecond)\n\treturn nil\n}","sourceCodeStart":1141,"sourceCodeEnd":1177,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish.go#L1141-L1177","documentation":"bindProducts wraps a clickModalSaveButton failure with this message. The save button inside the product-selection modal was found but clicking it failed (detached element, overlay, disabled state, or CDP error). Products selected in this pass may not be persisted, so the publish flow aborts.","triggerScenarios":"The modal re-rendered after product selection, removing/replacing the save button; the button is disabled (no products selected); an overlay covers it; or the page/browser context died.","commonSituations":"All product searches failed (failedProducts non-empty) so the save button is disabled; slow rendering between selection and save; modal closed unexpectedly by an error toast.","solutions":["Check the wrapped inner error for the actual click cause","Ensure at least one product was selected before saving (a disabled save button can't be clicked)","Wait for the button to be stable/visible before clicking","Retry the whole bindProducts call with a fresh modal if the modal was destroyed"],"exampleFix":"// before\nif err := clickModalSaveButton(modal); err != nil {\n    return errors.Wrap(err, \"点击保存按钮失败\")\n}\n// after\nif err := modal.WaitStable(); err != nil { return err }\nif err := clickModalSaveButton(modal); err != nil {\n    return errors.Wrap(err, \"点击保存按钮失败\")\n}","handlingStrategy":"validation","validationCode":"// ensure a product was selected so save is enabled\nif len(failedProducts) == len(products) {\n    return errors.New(\"无任何商品选中，保存按钮不可用\")\n}","typeGuard":null,"tryCatchPattern":"if err := bindProducts(ctx, page, products); err != nil {\n    if strings.Contains(err.Error(), \"点击保存按钮失败\") {\n        // abort publish or re-run bindProducts with a fresh modal\n    }\n}","preventionTips":["Only click save after at least one product selection succeeded","Wait for modal stability before clicking save","Watch for error toasts that close the modal mid-flow","Retry the full bind step if the modal was destroyed"],"tags":["go-rod","dom-click","modal"],"backgroundTag":"rod-click-element-detached","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"}