siyuan-note/siyuan · error
field [file] or [url] must not be empty
Error message
field [file] or [url] must not be empty
What it means
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.
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)
Example fix
// before
fetchPost("/api/emoji/addEmoji", {}, cb) // no file, no url
// after
fetchPost("/api/emoji/addEmoji", { url: "https://example.com/emoji.png" }, cb) Defensive patterns
Strategy: validation
Validate before calling
if (!file && !(url && url.trim())) {
throw new Error("Provide either a file upload or a non-empty url");
} Try / catch
try {
await addEmoji(payload);
} catch (e) {
if (String(e).includes("must not be empty")) promptUserForSource();
} Prevention
- 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)
When it happens
Trigger: Calling the emoji-add API (e.g. /api/emoji/addEmoji) with a request object whose File and URL fields are both empty/blank strings.
Common situations: 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.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- AI editor action must not be empty
- block [ ] type is locked: expected , got
- block swap requires two non-document blocks
- Bookmark cannot be empty
- can not remove [ ] caused by it is a reserved file
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/52cd0e6cdf332a90.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/api/system.go:331
relativePath = filepath.ToSlash(relativePath)
ret = apicontract.Success(apicontract.SystemPathData{Path: relativePath})
return
})
func readCustomEmojiData(request apicontract.SystemCustomEmojiRequest) ([]byte, error) {
fileHeader := request.File
if fileHeader != nil {
file, err := fileHeader.Open()
if err != nil {
return nil, err
}
defer file.Close()
return io.ReadAll(io.LimitReader(file, maxCustomEmojiSize+1))
}
rawURL := strings.TrimSpace(request.URL)
if rawURL == "" {
return nil, fmt.Errorf("field [file] or [url] must not be empty")
}
return downloadCustomEmojiData(rawURL)
}
func downloadCustomEmojiData(rawURL string) ([]byte, error) {
parsedURL, err := url.Parse(rawURL)
if err != nil || (parsedURL.Scheme != "http" && parsedURL.Scheme != "https") || parsedURL.Host == "" {
return nil, fmt.Errorf("invalid custom emoji URL")
}
response, err := util.NewCustomReqClient().R().Get(parsedURL.String())
if err != nil {
return nil, fmt.Errorf("download custom emoji failed: %w", err)
}
defer response.Body.Close()
if response.StatusCode != http.StatusOK {
return nil, fmt.Errorf("download custom emoji failed with status %d", response.StatusCode)
}View on GitHub (pinned to 9f775e8a12)