siyuan-note/siyuan · error
unsupported custom emoji image format
Error message
unsupported custom emoji image format
What it means
If the bytes are neither a recognized raster format (png/jpeg/gif/webp) nor a sanitizable SVG, normalizeCustomEmojiData gives up with 'unsupported custom emoji image format'. Only those image formats are accepted as custom emoji.
Solutions
- Convert the image to PNG (or WebP/JPEG/GIF) before using it as an emoji
- Remove scripts/unsafe elements from the SVG so sanitization succeeds
- Check the URL serves one of the supported formats (DetectContentType is content-based, extension is irrelevant)
- Verify the server is not returning an HTML page
Example fix
// before
host("logo.bmp")
// after
convertToPNG("logo.bmp", "logo.png") // PNG is always supported
host("logo.png") Defensive patterns
Strategy: fallback
Validate before calling
const type = (await fetch(url)).headers.get("content-type");
const ok = ["image/png","image/jpeg","image/gif","image/webp","image/svg+xml"].includes(type);
if (!ok) throw new Error(`format ${type} unsupported; convert to PNG`); Try / catch
try {
await registerEmoji(data);
} catch (e) {
if (String(e).includes("unsupported custom emoji image format")) {
const png = await convertToPNG(data); // fallback conversion
return registerEmoji(png);
}
throw e;
} Prevention
- Convert BMP/TIFF/ICO sources to PNG before use
- Sanitize SVGs (no scripts) before submission
- Check the served content type, not just the file extension
When it happens
Trigger: Downloading a file whose content type is not image/png, image/jpeg, image/gif, image/webp, or valid SVG — e.g. BMP, TIFF, ICO, PDF, or text — or an SVG that fails SanitizeSVG.
Common situations: User pastes a URL to an .ico favicon or .bmp image; server returns HTML instead of an image; SVG containing script is rejected by the sanitizer.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- color [ ] must use #RRGGBB format
- custom emoji file must not be empty
- generated image is empty
- generated image is invalid
- image data is empty
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/27012c04f9b390e9.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/api/system.go:392
case "image/webp":
ext = ".webp"
default:
raster = false
}
if raster {
config, _, decodeErr := image.DecodeConfig(bytes.NewReader(data))
if decodeErr != nil || config.Width < 1 || config.Height < 1 || config.Width > 16384 || config.Height > 16384 ||
int64(config.Width)*int64(config.Height) > 100*1000*1000 {
return nil, "", fmt.Errorf("invalid custom emoji image")
}
return data, ext, nil
}
sanitizedSVG, sanitizeErr := util.SanitizeSVG(string(data))
if sanitizeErr == nil {
return []byte(sanitizedSVG), ".svg", nil
}
return nil, "", fmt.Errorf("unsupported custom emoji image format")
}
func normalizeCustomEmojiPath(name, ext string) (string, error) {
name = strings.TrimSpace(strings.ReplaceAll(name, "\\", "/"))
parts := strings.Split(name, "/")
if len(parts) == 0 {
return "", fmt.Errorf("custom emoji name must not be empty")
}
lastIndex := len(parts) - 1
switch strings.ToLower(filepath.Ext(parts[lastIndex])) {
case ".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg":
parts[lastIndex] = strings.TrimSuffix(parts[lastIndex], filepath.Ext(parts[lastIndex]))
}
for i, part := range parts {
part = strings.TrimSpace(part)
if part == "" || part == "." || part == ".." {
return "", fmt.Errorf("invalid custom emoji name")View on GitHub (pinned to 9f775e8a12)