siyuan-note/siyuan · error
invalid custom emoji name
Error message
invalid custom emoji name
What it means
Each path component of the emoji name is trimmed and checked: empty strings, '.', and '..' are rejected as 'invalid custom emoji name' before any filtering, preventing path traversal and malformed names.
Solutions
- Remove '.', '..', and empty segments from the name
- Use a single flat filename like 'emoji.png' instead of a relative path with dot segments
- Sanitize user input before submitting to the API
- Never build emoji names from filesystem paths of untrusted origin
Example fix
// before
{"name": "../../emoji.png"}
// after
{"name": "emoji.png"} Defensive patterns
Strategy: validation
Validate before calling
const parts = name.replace(/\\/g, "/").split("/");
if (parts.some(p => ["", ".", ".."].includes(p.trim())))
throw new Error("emoji name contains invalid path segments"); Try / catch
try {
await registerEmoji({name});
} catch (e) {
if (String(e).includes("invalid custom emoji name")) {
notifyUser("Remove '.', '..', and empty segments from the name");
}
} Prevention
- Use flat filenames without path separators for emoji names
- Never build names from untrusted filesystem paths
- Strip dot-segments before submission
When it happens
Trigger: The emoji name contains a path component that is empty, '.', or '..' after trimming — e.g. name '../etc/passwd.png', 'a//b.png', or ' ./x.png'.
Common situations: Untrusted user input used directly as a filename; path traversal attempts; copy-paste errors leaving stray slashes or dots in the name.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- asset path escapes data directory
- asset path escapes data directory
- export path is outside export directory
- history path [ ] is not in workspace
- history path [ ] is not under history directory
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/7067ce79e9162b50.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/api/system.go:410
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")
}
part = util.FilterUploadFileName(part)
if part == "" || part == "." || part == ".." {
return "", fmt.Errorf("invalid custom emoji name")
}
parts[i] = part
}
parts[lastIndex] += ext
return strings.Join(parts, "/"), nil
}
var checkUpdate = contractHandler(apicontract.SystemCheckUpdate, func(c *gin.Context, request apicontract.SystemCheckUpdateRequest) (ret apicontract.Response[apicontract.Null]) {
ret = apicontract.Success(apicontract.Null{})
showMsg := request.ShowMsg
model.CheckUpdate(showMsg)
return
})View on GitHub (pinned to 9f775e8a12)