{"record":{"id":"4183cafe923b233f","repo":"xpzouying/xiaohongshu-mcp","slug":"downloaded-file-is-not-a-valid-image","errorCode":null,"errorMessage":"downloaded file is not a valid image","messagePattern":"downloaded file is not a valid image","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/downloader/images.go","lineNumber":86,"sourceCode":"\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"download failed with status %d for URL: %s\", resp.StatusCode, imageURL)\n\t}\n\n\t// 读取图片数据\n\timageData, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to read image data\")\n\t}\n\n\t// 检测图片格式\n\tkind, err := filetype.Match(imageData)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to detect file type\")\n\t}\n\n\tif !filetype.IsImage(imageData) {\n\t\treturn \"\", errors.New(\"downloaded file is not a valid image\")\n\t}\n\n\t// 生成唯一文件名\n\tfileName := d.generateFileName(imageURL, kind.Extension)\n\tfilePath := filepath.Join(d.savePath, fileName)\n\n\t// 如果文件已存在，直接返回路径\n\tif _, err := os.Stat(filePath); err == nil {\n\t\treturn filePath, nil\n\t}\n\n\t// 保存到文件\n\tif err := os.WriteFile(filePath, imageData, 0644); err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to save image\")\n\t}\n\n\treturn filePath, nil\n}","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/xpzouying/xiaohongshu-mcp/blob/332d196854a9eac0d2b8c2c0e3d0cc43139d724c/pkg/downloader/images.go#L68-L104","documentation":"After downloading, DownloadImage uses the filetype package to sniff the bytes; if filetype.IsImage fails it returns 'downloaded file is not a valid image'. This catches cases where the server responded 200 but the body is not an image (HTML error page, JSON, verification page, etc.).","triggerScenarios":"Downloading an image URL that returns a 200 response with HTML/JSON body — e.g. an anti-bot page, expired CDN link, or login redirect page. The check at pkg/downloader/images.go:86 `if !filetype.IsImage(imageData)` triggers.","commonSituations":"CDN URL expired and returns an XML/HTML error with status 200; XHS serves a captcha/verify page instead of the image; downloading with missing Referer/UA so the server returns a block page; saving an SVG/webp variant the sniffer doesn't classify as image.","solutions":["Set proper User-Agent and Referer headers on the downloader (the library already sends UA/Referer; verify they match the site's expectations)","Log the first bytes / content-type of the response to identify what the server actually returned","Re-extract a fresh image URL (CDN links expire) and retry the download","Handle the error per-image: skip the invalid one and continue the batch"],"exampleFix":"// before\npath, err := downloader.DownloadImage(url)\nif err != nil { return err }\n// after\npath, err := downloader.DownloadImage(url)\nif err != nil {\n    if strings.Contains(err.Error(), \"not a valid image\") {\n        log.Printf(\"non-image response for %s, refreshing URL\", url)\n        continue\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":"// pre-check response content type if you control the request\nreq.Header.Set(\"Referer\", \"https://www.xiaohongshu.com/\")","typeGuard":null,"tryCatchPattern":"path, err := downloader.DownloadImage(url)\nif err != nil && strings.Contains(err.Error(), \"not a valid image\") {\n    log.Printf(\"non-image body for %s, refreshing URL\", url)\n    continue // skip or re-fetch fresh CDN link\n}","preventionTips":["Send site-appropriate User-Agent and Referer headers","Detect anti-bot/verify pages early and refresh session","Treat per-image failures as skippable in batch downloads"],"tags":["download","file-type","validation","images"],"backgroundTag":"invalid-image-response","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"}