siyuan-note/siyuan · error
Field [assets] must not be empty
Error message
Field [assets] must not be empty
What it means
The /api/clipboard/prepareRichText request decoder requires the assets array to contain at least one element. An empty assets array passes the type check (it is an Array) but is rejected because preparing rich text with no assets is meaningless.
Solutions
- Ensure at least one asset object (with index and path) is included in the assets array
- Check upstream selection logic so the API is only called when there is content to prepare
- Handle the error client-side by skipping the call when the asset list is empty
Example fix
// before
fetchPost("/api/clipboard/prepareRichText", {assets: []})
// after
if (assets.length > 0) { fetchPost("/api/clipboard/prepareRichText", {assets}) } Defensive patterns
Strategy: validation
Validate before calling
if (!Array.isArray(assets) || assets.length === 0) throw new Error('assets must be a non-empty array'); Prevention
- Guard for empty selections before calling prepareRichText
- Only call the API when there is actual clipboard content
- Treat empty assets as a skip condition, not an error to send
When it happens
Trigger: POSTing {"assets": []} to /api/clipboard/prepareRichText, or omitting asset entries while building the payload programmatically.
Common situations: Frontend collects no selected blocks/assets before calling the API; a loop that conditionally appends assets never runs; copying an empty selection.
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
- Field [batch] must not be empty
- Field [groups] must not be empty
- Invalid rich clipboard asset at index
- Field [assets. .box] should be of type [String]
- Field [assets. ] should be of type [Object]
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/ad12d92cdf2c45b7.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/clipboard_input.go:22
"bytes"
"encoding/json"
"fmt"
"io"
"strings"
)
func init() {
PrepareRichText.decodeRequest = func(reader io.Reader) (request PrepareRichTextRequest, err error) {
fields, err := blockRequestFields(reader, "/api/clipboard/prepareRichText")
if err != nil {
return request, err
}
assets, err := legacyField[[]json.RawMessage](fields, "assets", "Array", true)
if err != nil {
return request, err
}
if len(assets) == 0 {
return request, fmt.Errorf("Field [assets] must not be empty")
}
request.Assets = make([]RichClipboardAsset, 0, len(assets))
for i, raw := range assets {
var asset map[string]json.RawMessage
if json.Unmarshal(raw, &asset) != nil || asset == nil {
return request, fmt.Errorf("Field [assets.%d] should be of type [Object]", i)
}
var index float64
var path, box string
if bytes.Equal(asset["index"], []byte("null")) || json.Unmarshal(asset["index"], &index) != nil || index < 0 || index != float64(int(index)) || json.Unmarshal(asset["path"], &path) != nil || strings.TrimSpace(path) == "" {
return request, fmt.Errorf("Invalid rich clipboard asset at index [%d]", i)
}
if value, exists := asset["box"]; exists {
if bytes.Equal(value, []byte("null")) || json.Unmarshal(value, &box) != nil {
return request, fmt.Errorf("Field [assets.%d.box] should be of type [String]", i)
}
}
request.Assets = append(request.Assets, RichClipboardAsset{Index: int(index), Path: strings.TrimSpace(path), Box: strings.TrimSpace(box)})View on GitHub (pinned to 9f775e8a12)