{"record":{"id":"52cd0e6cdf332a90","repo":"siyuan-note/siyuan","slug":"field-file-or-url-must-not-be-empty","errorCode":null,"errorMessage":"field [file] or [url] must not be empty","messagePattern":"field \\[file\\] or \\[url\\] must not be empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/api/system.go","lineNumber":331,"sourceCode":"\trelativePath = filepath.ToSlash(relativePath)\n\tret = apicontract.Success(apicontract.SystemPathData{Path: relativePath})\n\treturn\n})\n\nfunc readCustomEmojiData(request apicontract.SystemCustomEmojiRequest) ([]byte, error) {\n\tfileHeader := request.File\n\tif fileHeader != nil {\n\t\tfile, err := fileHeader.Open()\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tdefer file.Close()\n\t\treturn io.ReadAll(io.LimitReader(file, maxCustomEmojiSize+1))\n\t}\n\n\trawURL := strings.TrimSpace(request.URL)\n\tif rawURL == \"\" {\n\t\treturn nil, fmt.Errorf(\"field [file] or [url] must not be empty\")\n\t}\n\treturn downloadCustomEmojiData(rawURL)\n}\n\nfunc downloadCustomEmojiData(rawURL string) ([]byte, error) {\n\tparsedURL, err := url.Parse(rawURL)\n\tif err != nil || (parsedURL.Scheme != \"http\" && parsedURL.Scheme != \"https\") || parsedURL.Host == \"\" {\n\t\treturn nil, fmt.Errorf(\"invalid custom emoji URL\")\n\t}\n\n\tresponse, err := util.NewCustomReqClient().R().Get(parsedURL.String())\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"download custom emoji failed: %w\", err)\n\t}\n\tdefer response.Body.Close()\n\tif response.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"download custom emoji failed with status %d\", response.StatusCode)\n\t}","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/api/system.go#L313-L349","documentation":"readCustomEmojiData accepts an uploaded file or a `url` field for adding a custom emoji. When neither is provided (or url is only whitespace) it returns \"field [file] or [url] must not be empty\" because it has no data source to read.","triggerScenarios":"Calling the emoji-add API (e.g. /api/emoji/addEmoji) with a request object whose File and URL fields are both empty/blank strings.","commonSituations":"Frontend forms submitted before a file was chosen; a URL field containing only spaces; programmatic clients that forgot to set either field; API changes where the payload key was renamed so the field arrives empty.","solutions":["Provide either a multipart `file` upload or a non-empty `url` string in the request","Trim and check the URL client-side before submitting","Verify the client sends the field under the exact expected key (file / url)"],"exampleFix":"// before\nfetchPost(\"/api/emoji/addEmoji\", {}, cb) // no file, no url\n// after\nfetchPost(\"/api/emoji/addEmoji\", { url: \"https://example.com/emoji.png\" }, cb)","handlingStrategy":"validation","validationCode":"if (!file && !(url && url.trim())) {\n  throw new Error(\"Provide either a file upload or a non-empty url\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await addEmoji(payload);\n} catch (e) {\n  if (String(e).includes(\"must not be empty\")) promptUserForSource();\n}","preventionTips":["Disable the submit button until a file is chosen or a URL entered","Trim URL input before sending","Keep payload keys aligned with the API contract (file / url)"],"tags":["emoji","validation","empty-field","api"],"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"}