siyuan-note/siyuan · error
unsupported or invalid image:
Error message
unsupported or invalid image:
What it means
Thrown by util.PrepareModelImage (kernel/util/openai.go:730) when the MIME type passed the whitelist but Go's image.DecodeConfig cannot parse the image header. The magic bytes look right, yet the file structure is broken or uses a variant the registered decoders (stdlib gif/jpeg/png plus golang.org/x/image/webp) cannot read. The underlying stdlib error text is appended.
Solutions
- Re-export or re-download the original image and retry
- Verify integrity out-of-band (file, pngcheck -v, magick identify) and replace corrupt assets
- Round-trip convert with a tolerant tool (magick broken.png fixed.png) which often rebuilds a valid header
- Catch this error per-image in batch loops and skip the bad asset instead of failing the run
Example fix
// before
prepared, err := util.PrepareModelImage(data, maxBytes, maxPixels, maxEdge)
// after
if _, _, cfgErr := image.DecodeConfig(bytes.NewReader(data)); cfgErr != nil {
data = reencodeExternally(data) // magick in -out out.png rebuilds headers
}
prepared, err := util.PrepareModelImage(data, maxBytes, maxPixels, maxEdge) Defensive patterns
Strategy: validation
Validate before calling
if _, _, err := image.DecodeConfig(bytes.NewReader(data)); err != nil {
// header already broken: re-export or skip before calling PrepareModelImage
data = reencodeExternally(data)
} Try / catch
if err != nil && strings.HasPrefix(err.Error(), "unsupported or invalid image:") {
// asset bytes are corrupt past magic bytes: re-export source or skip asset
} Prevention
- Verify synced assets complete (size/checksum) before analysis
- Run pngcheck or magick identify on suspicious assets
- Treat header-decode failure as permanent for that file; re-export, do not retry unchanged
When it happens
Trigger: Truncated download or partially copied asset (valid signature, cut off before IHDR/VP8 header); PNG with corrupt IHDR; extended/animated WebP that x/image/webp rejects; header fields encoding zero or absurd dimensions.
Common situations: Assets damaged by interrupted sync or copy-on-write races, web-clipped images cut off mid-download, WebP files from encoders producing animation or feature chunks Go cannot parse.
Related errors
- decode image failed:
- encode image failed:
- decode existing session data failed
- decode session data failed
- encrypted notebook has no valid key material
AI-assisted analysis of siyuan-note/siyuan@afa823b6b4 (2026-08-18).
Data as JSON: /api/errors/ba81e870a04f4e3d.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/util/openai.go:730
func PrepareModelImage(data []byte, maxBytes, maxPixels, maxEdge int) (PreparedImage, error) {
if len(data) == 0 {
return PreparedImage{}, errors.New("image data is empty")
}
if maxBytes > 0 && len(data) > maxBytes {
return PreparedImage{}, fmt.Errorf("image exceeds size limit: %d bytes", maxBytes)
}
mimeType := mimetype.Detect(data).String()
if strings.Contains(mimeType, "svg") || bytes.Contains(bytes.ToLower(data[:min(len(data), 512)]), []byte("<svg")) {
return PreparedImage{}, errors.New("SVG images are not accepted by multimodal models")
}
switch mimeType {
case "image/gif", "image/jpeg", "image/png", "image/webp":
default:
return PreparedImage{}, fmt.Errorf("unsupported image type: %s", mimeType)
}
config, _, err := image.DecodeConfig(bytes.NewReader(data))
if err != nil {
return PreparedImage{}, errors.New("unsupported or invalid image: " + err.Error())
}
if config.Width < 1 || config.Height < 1 || maxPixels > 0 && int64(config.Width)*int64(config.Height) > int64(maxPixels) {
return PreparedImage{}, fmt.Errorf("image exceeds pixel limit: %d", maxPixels)
}
decoded, err := imaging.Decode(bytes.NewReader(data), imaging.AutoOrientation(true))
if err != nil {
return PreparedImage{}, errors.New("decode image failed: " + err.Error())
}
bounds := decoded.Bounds()
needsResize := maxEdge > 0 && (bounds.Dx() > maxEdge || bounds.Dy() > maxEdge)
if !needsResize && bounds.Dx() == config.Width && bounds.Dy() == config.Height && mimeType != "image/gif" {
return PreparedImage{
Data: data,
MIMEType: mimeType,
Width: bounds.Dx(),
Height: bounds.Dy(),
SourceSize: len(data),View on GitHub (pinned to afa823b6b4)