siyuan-note/siyuan · error
invalid rich clipboard asset index
Error message
invalid rich clipboard asset index [%d]
What it means
PrepareRichClipboardAssets rejects any asset whose Index is negative, returning fmt.Errorf("invalid rich clipboard asset index [%d]", asset.Index) at kernel/model/clipboard.go:83. Each RichClipboardAsset must carry a zero-based index so the pasted content can reassemble images in the original order. A negative index indicates the producer serialized the clipboard payload incorrectly.
Solutions
- Fix the producer so indices are sequential zero-based values (0,1,2,...) matching the order of occurrences in the pasted content
- Validate/normalize the payload before calling the kernel: reject or clamp negative indices and surface a client-side error
- If -1 means 'unset', assign the correct position explicitly instead of relying on the sentinel
- Note the error already triggers deferred cleanup, so no partial prepared batch leaks; just fix the input
Example fix
// before
assets = append(assets, RichClipboardAsset{Index: -1, Path: p})
// after
for i, p := range paths {
assets = append(assets, RichClipboardAsset{Index: i, Path: p})
} Defensive patterns
Strategy: validation
Validate before calling
for i, a := range assets {
if a.Index < 0 { return fmt.Errorf("asset %d has invalid index %d", i, a.Index) }
} Prevention
- Generate indices from a loop counter, never hand-assign them
- Avoid -1 as an 'unset' sentinel in serialized payloads; set the real position
When it happens
Trigger: Submitting a RichClipboardAsset with Index set to -1 (often used as an 'unknown/unset' sentinel by caller code) or an uninitialized struct where Index defaulted but was later decremented; an off-by-one loop that emits -1 for the first element.
Common situations: Frontend code using -1 as 'no position' and passing it through; hand-crafted API payloads in tests or plugins; struct fields assigned in the wrong order when building the assets array.
Related errors
- Field [assets. .box] should be of type [String]
- Field [assets. ] should be of type [Object]
- Field [assets] must not be empty
- Field [batch] must not be empty
- Field [groups. ] should be of type [String]
AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19).
Data as JSON: /api/errors/721fcc2ce9b58970.
Report an issue: GitHub.
Appendix: source
Thrown at kernel/model/clipboard.go:83
func PrepareRichClipboardAssets(assets []RichClipboardAsset) (ret *RichClipboardPrepared, err error) {
if len(assets) < 1 || 1024 < len(assets) {
return nil, fmt.Errorf("invalid rich clipboard asset count [%d]", len(assets))
}
batch := util.RandString(24)
groups := map[string]struct{}{}
copied := map[string]string{}
ret = &RichClipboardPrepared{Batch: batch}
defer func() {
if err != nil {
cleanupRichClipboardGroups(batch, groups)
}
}()
for _, asset := range assets {
if asset.Index < 0 {
return nil, fmt.Errorf("invalid rich clipboard asset index [%d]", asset.Index)
}
ext := strings.ToLower(filepath.Ext(AssetPathWithoutQuery(asset.Path)))
if _, ok := richClipboardImageExts[ext]; !ok {
return nil, fmt.Errorf("unsupported rich clipboard image extension [%s]", ext)
}
absPath, resolveErr := GetAssetAbsPathInBox(asset.Path, asset.Box)
if resolveErr != nil {
return nil, resolveErr
}
if ensureErr := ensureReadableAssetLocal(absPath); ensureErr != nil {
return nil, ensureErr
}
destPath, ok := copied[absPath]
if !ok {
group := ExtractBoxIDFromAssetsPath(absPath)View on GitHub (pinned to 9f775e8a12)