xpzouying/xiaohongshu-mcp · error
failed to save image
Error message
failed to save image
What it means
After the image bytes pass format validation, DownloadImage writes them with os.WriteFile into the configured savePath. This error wraps any filesystem failure from that write: the save directory missing/removed at runtime, insufficient permissions, disk full, or the resolved path being invalid (e.g. a file where a directory is expected).
Source
Thrown at pkg/downloader/images.go:100
return "", errors.Wrap(err, "failed to detect file type")
}
if !filetype.IsImage(imageData) {
return "", errors.New("downloaded file is not a valid image")
}
// 生成唯一文件名
fileName := d.generateFileName(imageURL, kind.Extension)
filePath := filepath.Join(d.savePath, fileName)
// 如果文件已存在,直接返回路径
if _, err := os.Stat(filePath); err == nil {
return filePath, nil
}
// 保存到文件
if err := os.WriteFile(filePath, imageData, 0644); err != nil {
return "", errors.Wrap(err, "failed to save image")
}
return filePath, nil
}
// DownloadImages 批量下载图片
func (d *ImageDownloader) DownloadImages(imageURLs []string) ([]string, error) {
var localPaths []string
var errs []error
for _, imageURL := range imageURLs {
localPath, err := d.DownloadImage(imageURL)
if err != nil {
errs = append(errs, fmt.Errorf("failed to download %s: %w", imageURL, err))
continue
}
localPaths = append(localPaths, localPath)
}View on GitHub (pinned to 332d196854)
Solutions
- Check the wrapped err with errors.Cause / %v for the exact OS reason (ENOENT, EACCES, ENOSPC) and fix accordingly
- Ensure the directory exists before downloading: os.MkdirAll(savePath, 0755) (NewImageDownloader only does it once at construction)
- Verify write permission: ls -ld <savePath>, or run with a user that can write; in containers mount a writable volume
- Check disk space (df -h) if the cause is ENOSPC
Example fix
// before
if err := os.WriteFile(filePath, imageData, 0644); err != nil {
return "", errors.Wrap(err, "failed to save image")
}
// after
if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
return "", errors.Wrap(err, "failed to ensure save dir")
}
if err := os.WriteFile(filePath, imageData, 0644); err != nil {
return "", errors.Wrap(err, "failed to save image")
} Defensive patterns
Strategy: validation
Validate before calling
// 下载前确保目录存在且可写
if err := os.MkdirAll(savePath, 0755); err != nil {
return err
}
test := filepath.Join(savePath, ".write_test")
if err := os.WriteFile(test, nil, 0644); err != nil {
return fmt.Errorf("savePath not writable: %w", err)
}
os.Remove(test) Type guard
func isSavePathWritable(dir string) bool {
info, err := os.Stat(dir)
return err == nil && info.IsDir()
} Try / catch
path, err := d.DownloadImage(url)
if err != nil {
var pathErr *os.PathError
if errors.As(err, &pathErr) {
log.Printf("filesystem error saving image: %v (dir=%s)", pathErr.Err, savePath)
// 修复目录后重试一次
os.MkdirAll(savePath, 0755)
return d.DownloadImage(url)
}
return "", err
} Prevention
- Call os.MkdirAll on the savePath at each batch start, not only in the constructor
- Mount a writable volume in containers and verify with a write test at startup
- Use absolute savePath to avoid CWD-dependent relative paths
- Monitor disk space when downloading in bulk
When it happens
Trigger: Calling DownloadImage/DownloadImages when: savePath directory was deleted after NewImageDownloader ran; process lacks write permission on savePath; disk quota/full; the generated file path collides with an existing directory entry.
Common situations: Running the app in a container with a read-only or not-mounted volume path; savePath configured as a relative path while CWD changed; tmp cleaner removed the directory between program start and download; running as non-root user writing to a root-owned folder.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
Related errors
- create cookies dir failed
- 视频文件不存在或不可访问: %v
- failed to read cookies from tmp file
- 视频文件不存在: %s
- failed to create save path: %v
AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05).
Data as JSON: /api/errors/80962343e29780e5.
Report an issue: GitHub.