{"record":{"id":"3b9f1844f016145c","repo":"siyuan-note/siyuan","slug":"custom-emoji-name-must-not-be-empty","errorCode":null,"errorMessage":"custom emoji name must not be empty","messagePattern":"custom emoji name must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/api/system.go","lineNumber":399,"sourceCode":"\t\tif decodeErr != nil || config.Width < 1 || config.Height < 1 || config.Width > 16384 || config.Height > 16384 ||\n\t\t\tint64(config.Width)*int64(config.Height) > 100*1000*1000 {\n\t\t\treturn nil, \"\", fmt.Errorf(\"invalid custom emoji image\")\n\t\t}\n\t\treturn data, ext, nil\n\t}\n\n\tsanitizedSVG, sanitizeErr := util.SanitizeSVG(string(data))\n\tif sanitizeErr == nil {\n\t\treturn []byte(sanitizedSVG), \".svg\", nil\n\t}\n\treturn nil, \"\", fmt.Errorf(\"unsupported custom emoji image format\")\n}\n\nfunc normalizeCustomEmojiPath(name, ext string) (string, error) {\n\tname = strings.TrimSpace(strings.ReplaceAll(name, \"\\\\\", \"/\"))\n\tparts := strings.Split(name, \"/\")\n\tif len(parts) == 0 {\n\t\treturn \"\", fmt.Errorf(\"custom emoji name must not be empty\")\n\t}\n\n\tlastIndex := len(parts) - 1\n\tswitch strings.ToLower(filepath.Ext(parts[lastIndex])) {\n\tcase \".png\", \".jpg\", \".jpeg\", \".gif\", \".webp\", \".svg\":\n\t\tparts[lastIndex] = strings.TrimSuffix(parts[lastIndex], filepath.Ext(parts[lastIndex]))\n\t}\n\tfor i, part := range parts {\n\t\tpart = strings.TrimSpace(part)\n\t\tif part == \"\" || part == \".\" || part == \"..\" {\n\t\t\treturn \"\", fmt.Errorf(\"invalid custom emoji name\")\n\t\t}\n\t\tpart = util.FilterUploadFileName(part)\n\t\tif part == \"\" || part == \".\" || part == \"..\" {\n\t\t\treturn \"\", fmt.Errorf(\"invalid custom emoji name\")\n\t\t}\n\t\tparts[i] = part\n\t}","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/api/system.go#L381-L417","documentation":"normalizeCustomEmojiPath builds a safe relative path from the user-supplied emoji name. Because strings.Split never returns an empty slice, the len(parts)==0 guard is effectively defensive; the error 'custom emoji name must not be empty' signals that no usable name/path was supplied for the emoji.","triggerScenarios":"Calling the emoji-registration path with an empty/whitespace-only name; after backslash normalization and splitting, no path components remain.","commonSituations":"Client sends the API an empty name field; frontend form not filled in; scripted API call omitting the name parameter.","solutions":["Supply a non-empty emoji name in the request","Trim and validate the name on the client before calling the API","Check that the field is not being dropped by your HTTP client serialization","Use a meaningful filename as the emoji name"],"exampleFix":"// before\n{\"name\": \"\"}\n// after\n{\"name\": \"smile.png\"}","handlingStrategy":"validation","validationCode":"const name = (form.name || \"\").trim();\nif (!name) throw new Error(\"emoji name is required\");","typeGuard":null,"tryCatchPattern":"try {\n  await registerEmoji(payload);\n} catch (e) {\n  if (String(e).includes(\"name must not be empty\")) {\n    notifyUser(\"Provide a non-empty emoji name\");\n  }\n}","preventionTips":["Require the name field in UI forms (non-empty validation)","Trim inputs before sending","Don't omit the name parameter in scripted API calls"],"tags":["validation","path","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}