{"record":{"id":"8e017ba6c8da00fb","repo":"xpzouying/xiaohongshu-mcp","slug":"error-8e017b","errorCode":null,"errorMessage":"点击添加商品按钮失败","messagePattern":"点击添加商品按钮失败","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"xiaohongshu/publish.go","lineNumber":1135,"sourceCode":"\t\treturn true\n\t}\n\tif cls, _ := btn.Attribute(\"class\"); cls != nil && hasExactClass(*cls, \"disabled\") {\n\t\treturn true\n\t}\n\treturn false\n}\n\n// bindProducts 绑定商品到发布内容\nfunc bindProducts(ctx context.Context, page *rod.Page, products []string) error {\n\tif len(products) == 0 {\n\t\treturn nil\n\t}\n\n\tslog.Info(\"开始绑定商品\", \"products\", products)\n\n\t// 点击\"添加商品\"按钮\n\tif err := clickAddProductButton(page); err != nil {\n\t\treturn errors.Wrap(err, \"点击添加商品按钮失败\")\n\t}\n\ttime.Sleep(1 * time.Second)\n\n\t// 等待商品选择弹窗出现\n\tmodal, err := waitForProductModal(page)\n\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)","sourceCodeStart":1117,"sourceCodeEnd":1153,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/xiaohongshu/publish.go#L1117-L1153","documentation":"bindProducts wraps a clickAddProductButton failure with this message. That helper searches all span.d-text elements for the exact text '添加商品' and walks up to a clickable parent; failing means the button wasn't found or its click failed. Product binding cannot proceed and the whole publish submission errors out.","triggerScenarios":"The publish page has no '添加商品' span (page not fully loaded, no product module for the account, or text/selector changed), or page.Elements(\"span.d-text\")/humanize.Click returned an error.","commonSituations":"Page still loading when bindProducts runs (fixed sleeps only); account without e-commerce permission so the button isn't rendered; frontend redesign renaming the text or d-text class.","solutions":["Increase the wait before searching or poll for the '添加商品' span with a deadline","Verify the account has product-binding permission (button renders only then)","Log all span.d-text texts when not found to detect text changes","Update the selector/text constant if the frontend changed"],"exampleFix":"// before\nspans, err := page.Elements(\"span.d-text\")\n// after\nvar span *rod.Element\nerr := rod.Try(func() error {\n    el, e := page.Timeout(10*time.Second).ElementR(\"span.d-text\", \"添加商品\")\n    span = el; return e\n})","handlingStrategy":"validation","validationCode":"// confirm the add-product entry exists before binding\nif _, err := page.ElementR(\"span.d-text\", \"添加商品\"); err != nil {\n    return fmt.Errorf(\"添加商品入口不可用（检查账号权限/页面加载）: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err := bindProducts(ctx, page, products); err != nil {\n    if strings.Contains(err.Error(), \"点击添加商品按钮失败\") {\n        // skip product binding or abort publish with a clear reason\n    }\n}","preventionTips":["Wait for the publish page fully loaded before bindProducts","Verify the account has product-binding permission","Poll for the '添加商品' text with a timeout instead of fixed sleeps","Alert on frontend text changes by logging all span.d-text values on miss"],"tags":["go-rod","dom-selector","products"],"backgroundTag":"selector-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"}