siyuan-note/siyuan · error

SVG images are not accepted by multimodal models

Error message

SVG images are not accepted by multimodal models

What it means

PrepareModelImage rejects SVG images because multimodal model APIs do not accept vector SVG payloads. Detection is twofold: the mimetype library's result containing 'svg', or a literal '<svg' byte sequence in the first 512 bytes. This catches both properly typed SVG files and SVG content served with a wrong or missing content type.

Solutions

  1. Convert the SVG to PNG (or JPEG/WebP) before attaching it to an AI conversation
  2. Render the SVG at a target resolution with a rasterizer (browser, resvg, sharp) and use the raster output
  3. If the image is a diagram, export it from the diagram tool directly as PNG instead of SVG
  4. If you only need the content described, paste the SVG's source text into the chat instead of attaching it as an image

Example fix

// before
prepared, err := PrepareModelImage(svgBytes, maxBytes, maxPixels, maxEdge) // SVG rejected
// after
pngBytes := rasterizeSVG(svgBytes, 1024, 1024) // render to PNG first
prepared, err := PrepareModelImage(pngBytes, maxBytes, maxPixels, maxEdge)
Defensive patterns

Strategy: validation

Validate before calling

if bytes.Contains(bytes.ToLower(data[:min(len(data),512)]), []byte("<svg")) {
    data = rasterizeSVG(data, 1024) // convert before the pipeline rejects it
}

Type guard

func isRasterImage(mt string) bool {
    switch mt {
    case "image/gif", "image/jpeg", "image/png", "image/webp":
        return true
    }
    return false
}

Try / catch

prepared, err := PrepareModelImage(data, maxBytes, maxPixels, maxEdge)
if err != nil && strings.Contains(err.Error(), "SVG") {
    prepared, err = PrepareModelImage(rasterizeSVG(data, 1024), maxBytes, maxPixels, maxEdge)
}

Prevention

When it happens

Trigger: Calling PrepareModelImage on an .svg asset — e.g. dragging an SVG icon/diagram into an AI chat with a multimodal model, or an asset whose first 512 bytes contain '<svg'.

Common situations: Inserting icons, logos, or mermaid/plantuml-exported SVG diagrams then referencing them in AI chats; assets saved from the web with SVG content but a PNG-like name.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/90e471907c5e6fc8. Report an issue: GitHub.

Appendix: source

Thrown at kernel/util/openai.go:770

			return
		}
		seen[index] = true
	}
	matched = true
	return
}

// PrepareModelImage 校验并按需缩放图片,尽量保留多模态模型支持的原始格式和图片质量。
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())
	}

View on GitHub (pinned to 9f775e8a12)