xpzouying/xiaohongshu-mcp · error

downloaded file is not a valid image

Error message

downloaded file is not a valid image

What it means

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.).

Source

Thrown at pkg/downloader/images.go:86

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("download failed with status %d for URL: %s", resp.StatusCode, imageURL)
	}

	// 读取图片数据
	imageData, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", errors.Wrap(err, "failed to read image data")
	}

	// 检测图片格式
	kind, err := filetype.Match(imageData)
	if err != nil {
		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
}

View on GitHub (pinned to 332d196854)

Solutions

  1. Set proper User-Agent and Referer headers on the downloader (the library already sends UA/Referer; verify they match the site's expectations)
  2. Log the first bytes / content-type of the response to identify what the server actually returned
  3. Re-extract a fresh image URL (CDN links expire) and retry the download
  4. Handle the error per-image: skip the invalid one and continue the batch

Example fix

// before
path, err := downloader.DownloadImage(url)
if err != nil { return err }
// after
path, err := downloader.DownloadImage(url)
if err != nil {
    if strings.Contains(err.Error(), "not a valid image") {
        log.Printf("non-image response for %s, refreshing URL", url)
        continue
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check response content type if you control the request
req.Header.Set("Referer", "https://www.xiaohongshu.com/")

Try / catch

path, err := downloader.DownloadImage(url)
if err != nil && strings.Contains(err.Error(), "not a valid image") {
    log.Printf("non-image body for %s, refreshing URL", url)
    continue // skip or re-fetch fresh CDN link
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of xpzouying/xiaohongshu-mcp@332d196854 (2026-09-05). Data as JSON: /api/errors/4183cafe923b233f. Report an issue: GitHub.