xpzouying/xiaohongshu-mcp · error
小红书上传图片失败
Error message
小红书上传图片失败
What it means
Publish uploads the provided image files into the creator publish page via uploadImages (typically rod's file-input setting plus DOM interaction). '小红书上传图片失败' wraps any error from that step: the upload button/input selector wasn't found, a file path doesn't exist or is unreadable, the file dialog/set-files CDP call failed, or the upload stalled. It does not cover later submit failures (those get '小红书发布失败').
Source
Thrown at xiaohongshu/publish.go:82
}
time.Sleep(1 * time.Second)
return &PublishAction{
page: pp,
}, nil
}
func (p *PublishAction) Publish(ctx context.Context, content PublishImageContent) error {
if len(content.ImagePaths) == 0 {
return errors.New("图片不能为空")
}
// 重设超时:.Context(ctx) 会替换掉 NewPublishImageAction 里 Timeout(300s) 的 deadline
page := p.page.Context(ctx).Timeout(300 * time.Second)
if err := uploadImages(page, content.ImagePaths); err != nil {
return errors.Wrap(err, "小红书上传图片失败")
}
tags := content.Tags
if len(tags) >= 10 {
logrus.Warnf("标签数量超过10,截取前10个标签")
tags = tags[:10]
}
logrus.Infof("发布内容: title=%s, images=%v, tags=%v, schedule=%v, original=%v, visibility=%s, products=%v", content.Title, len(content.ImagePaths), tags, content.ScheduleTime, content.IsOriginal, content.Visibility, content.Products)
if err := submitPublish(ctx, page, content.Title, content.Content, tags, content.ScheduleTime, content.IsOriginal, content.Visibility, content.Products); err != nil {
return errors.Wrap(err, "小红书发布失败")
}
return nil
}
// hasPopCover 当前页面是否还有挡人的浮层。View on GitHub (pinned to 332d196854)
Solutions
- Validate every path before calling Publish: os.Stat each entry in ImagePaths and convert to absolute paths
- Check the wrapped inner error printed by errors.Wrap to see whether it's a selector miss (fix selector) or a file error (fix path)
- Convert images to JPEG/PNG under the site's size limit (typically ~32MB each, ≤18 images per post)
- Re-run with a longer ctx budget if uploading many large images; Publish resets to a 300s timeout
- If a selector miss, dump the upload area HTML and update the input selector in uploadImages
Example fix
// before
err := action.Publish(ctx, content) // ImagePaths: ["./pic/a.jpg"] relative path
// after
for i, p := range content.ImagePaths {
abs, err := filepath.Abs(p)
if err != nil || !fileExists(abs) { return fmt.Errorf("image not found: %s", p) }
content.ImagePaths[i] = abs
}
err := action.Publish(ctx, content) Defensive patterns
Strategy: validation
Validate before calling
func validateImagePaths(paths []string) error {
if len(paths) == 0 { return errors.New("images required") }
for _, p := range paths {
abs, err := filepath.Abs(p)
if err != nil { return err }
info, err := os.Stat(abs)
if err != nil { return fmt.Errorf("image missing: %s", p) }
if info.Size() > 32<<20 { return fmt.Errorf("image too large: %s", p) }
}
return nil
} Type guard
func allImagesReadable(paths []string) bool {
for _, p := range paths {
f, err := os.Open(p)
if err != nil { return false }
f.Close()
}
return len(paths) > 0
} Try / catch
if err := action.Publish(ctx, content); err != nil {
if strings.Contains(err.Error(), "小红书上传图片失败") {
// inspect wrapped cause: file path vs selector vs timeout
log.Printf("upload failed: %+v", err)
}
return err
} Prevention
- Pre-validate every ImagePaths entry with os.Stat and filepath.Abs before Publish
- Use absolute paths — the browser process may have a different working directory than your Go program
- Keep images within the site's limits (JPEG/PNG, ~32MB, ≤18 images) and pre-convert otherwise
- Give Publish a generous ctx; the 300s internal timeout also needs the ctx budget to cover large uploads
When it happens
Trigger: content.ImagePaths contains a path that doesn't exist or isn't readable by the browser process; ImagePaths is empty (though that's caught earlier with '图片不能为空'); the upload input selector no longer matches after a site change; the images exceed xiaohongshu's size/count/format limits so the page rejects them; the 300s timeout expires on slow uploads of large files.
Common situations: Passing relative paths when the browser runs in a different working directory or container (headless server); HEIC/oversized images the site refuses; more images than the site's per-post limit; a site redesign moving the upload input so SetFiles can't find it.
Related errors
AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05).
Data as JSON: /api/errors/d9aa8e0920455c12.
Report an issue: GitHub.