{"record":{"id":"31fad8b4fb1333cf","repo":"xpzouying/xiaohongshu-mcp","slug":"download-errors-occurred-v","errorCode":null,"errorMessage":"download errors occurred: %v","messagePattern":"download errors occurred: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/downloader/images.go","lineNumber":121,"sourceCode":"\treturn filePath, nil\n}\n\n// DownloadImages 批量下载图片\nfunc (d *ImageDownloader) DownloadImages(imageURLs []string) ([]string, error) {\n\tvar localPaths []string\n\tvar errs []error\n\n\tfor _, imageURL := range imageURLs {\n\t\tlocalPath, err := d.DownloadImage(imageURL)\n\t\tif err != nil {\n\t\t\terrs = append(errs, fmt.Errorf(\"failed to download %s: %w\", imageURL, err))\n\t\t\tcontinue\n\t\t}\n\t\tlocalPaths = append(localPaths, localPath)\n\t}\n\n\tif len(errs) > 0 {\n\t\treturn localPaths, fmt.Errorf(\"download errors occurred: %v\", errs)\n\t}\n\n\treturn localPaths, nil\n}\n\n// isValidImageURL 检查是否为有效的图片URL\nfunc (d *ImageDownloader) isValidImageURL(rawURL string) bool {\n\t// 检查是否以http/https开头\n\tif !strings.HasPrefix(strings.ToLower(rawURL), \"http://\") &&\n\t\t!strings.HasPrefix(strings.ToLower(rawURL), \"https://\") {\n\t\treturn false\n\t}\n\n\t// 检查URL格式\n\tparsedURL, err := url.Parse(rawURL)\n\tif err != nil {\n\t\treturn false\n\t}","sourceCodeStart":103,"sourceCodeEnd":139,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/pkg/downloader/images.go#L103-L139","documentation":"DownloadImages downloads multiple images and aggregates per-image failures instead of failing on the first error. If any image download fails, it returns the successfully downloaded local paths plus a single wrapped error listing all individual failures. It is thrown to signal partial failure: some images may still be usable (returned in localPaths).","triggerScenarios":"Calling DownloadImages with one or more URLs that fail to download (network error, HTTP non-200, timeout, invalid image URL filtered upstream). Any failed item is appended to errs, and the aggregate error is returned at the end of the loop.","commonSituations":"Batch-processing article/Markdown content where some remote image hosts are dead, rate-limited, or blocking hotlinking; expired CDN URLs; DNS failures in restricted network environments.","solutions":["Inspect the wrapped %v error list to identify which URLs failed and verify each URL with a curl/HTTP GET to confirm accessibility","Re-run download for only the failed URLs (localPaths already contains successful ones)","Use IsImageURL to pre-filter malformed URLs before calling DownloadImages","Add proxy configuration or retry with backoff for flaky remote hosts"],"exampleFix":"// before\nlocalPaths, err := downloader.DownloadImages(ctx, urls)\nif err != nil {\n    return err // loses the successful paths\n}\n// after\nlocalPaths, err := downloader.DownloadImages(ctx, urls)\nif err != nil {\n    log.Warnf(\"partial download: %v\", err) // localPaths still has succeeded images\n    if len(localPaths) == 0 { return err }\n}","handlingStrategy":"try-catch","validationCode":"for _, u := range urls {\n    if !IsImageURL(u) { return fmt.Errorf(\"invalid image url: %s\", u) }\n}\nresp, err := http.Head(u)\nif err != nil || resp.StatusCode >= 400 { return fmt.Errorf(\"unreachable: %s\", u) }","typeGuard":"func isDownloadableImage(u string) bool {\n    if !IsImageURL(u) { return false }\n    resp, err := http.Head(u)\n    return err == nil && resp.StatusCode < 400\n}","tryCatchPattern":"localPaths, err := downloader.DownloadImages(ctx, urls)\nif err != nil {\n    var dlErr = fmt.Sprintf(\"%v\", err)\n    log.Printf(\"partial downloads, failed set: %s\", dlErr)\n    if len(localPaths) == 0 {\n        return fmt.Errorf(\"all images failed to download: %w\", err)\n    }\n    // proceed with partial results\n}","preventionTips":["Pre-filter URLs with IsImageURL before batch download","Health-check remote image hosts (HTTP HEAD) before batch submission","Pin or mirror volatile CDN assets to your own storage before publishing","Log the per-URL failures inside the wrapped error for targeted retries"],"tags":["go","downloader","network","partial-failure"],"backgroundTag":"image-download-failed","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"}