siyuan-note/siyuan · error
Field [assets. ] should be of type [Object]
Error message
Field [assets.%d] should be of type [Object]
What it means
Each element of the assets array in /api/clipboard/prepareRichText must be a JSON object. This error fires when an element fails to unmarshal into an object (e.g. it is a string, number, or array) or unmarshals to a nil map.
Solutions
- Send each asset as an object with at least a non-negative integer index and a non-empty string path
- Validate the payload shape before sending (typeof item === 'object' && !Array.isArray(item))
- Check for double JSON encoding — a JSON-stringified object inside the array will arrive as a string
Example fix
// before
{assets: ["/assets/foo.png"]}
// after
{assets: [{index: 0, path: "/assets/foo.png"}]} Defensive patterns
Strategy: type-guard
Validate before calling
assets.forEach((a, i) => { if (typeof a !== 'object' || a === null || Array.isArray(a)) throw new Error(`assets[${i}] must be an object`); }); Type guard
const isAssetObject = (a) => typeof a === 'object' && a !== null && !Array.isArray(a);
Prevention
- Never JSON.stringify elements inside the array (double encoding)
- Construct assets with an explicit builder function
- Diff payload shape against docs/API-CONTRACTS.md after upgrades
When it happens
Trigger: Sending assets: ["foo"], [123], [[]], or [null] to /api/clipboard/prepareRichText instead of an array of objects like [{"index":0,"path":"..."}].
Common situations: Serializing asset IDs/paths directly instead of asset objects; a JSON producer double-encoding assets as strings; mixing old string-based asset payloads with the newer object schema after an API version change.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Field [assets. .box] should be of type [String]
- Field [groups. ] should be of type [String]
- attr must be a string or null (got %T)
- block [ ] type is locked: expected , got
- createDocTree definition must be a list
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/76c7ebeff1303ed1.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/apicontract/clipboard_input.go:28
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)})
}
return
}
CleanupRichText.decodeRequest = func(reader io.Reader) (request CleanupRichTextRequest, err error) {
fields, err := blockRequestFields(reader, "/api/clipboard/cleanupRichText")
if err != nil {View on GitHub (pinned to 9f775e8a12)