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

  1. Provide either a multipart `file` upload or a non-empty `url` string in the request
  2. Trim and check the URL client-side before submitting
  3. 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

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-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)