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

  1. Fix the producer so indices are sequential zero-based values (0,1,2,...) matching the order of occurrences in the pasted content
  2. Validate/normalize the payload before calling the kernel: reject or clamp negative indices and surface a client-side error
  3. If -1 means 'unset', assign the correct position explicitly instead of relying on the sentinel
  4. 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

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


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)