{"record":{"id":"721fcc2ce9b58970","repo":"siyuan-note/siyuan","slug":"invalid-rich-clipboard-asset-index-d","errorCode":null,"errorMessage":"invalid rich clipboard asset index [%d]","messagePattern":"invalid rich clipboard asset index \\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/clipboard.go","lineNumber":83,"sourceCode":"\nfunc PrepareRichClipboardAssets(assets []RichClipboardAsset) (ret *RichClipboardPrepared, err error) {\n\tif len(assets) < 1 || 1024 < len(assets) {\n\t\treturn nil, fmt.Errorf(\"invalid rich clipboard asset count [%d]\", len(assets))\n\t}\n\n\tbatch := util.RandString(24)\n\tgroups := map[string]struct{}{}\n\tcopied := map[string]string{}\n\tret = &RichClipboardPrepared{Batch: batch}\n\tdefer func() {\n\t\tif err != nil {\n\t\t\tcleanupRichClipboardGroups(batch, groups)\n\t\t}\n\t}()\n\n\tfor _, asset := range assets {\n\t\tif asset.Index < 0 {\n\t\t\treturn nil, fmt.Errorf(\"invalid rich clipboard asset index [%d]\", asset.Index)\n\t\t}\n\n\t\text := strings.ToLower(filepath.Ext(AssetPathWithoutQuery(asset.Path)))\n\t\tif _, ok := richClipboardImageExts[ext]; !ok {\n\t\t\treturn nil, fmt.Errorf(\"unsupported rich clipboard image extension [%s]\", ext)\n\t\t}\n\n\t\tabsPath, resolveErr := GetAssetAbsPathInBox(asset.Path, asset.Box)\n\t\tif resolveErr != nil {\n\t\t\treturn nil, resolveErr\n\t\t}\n\t\tif ensureErr := ensureReadableAssetLocal(absPath); ensureErr != nil {\n\t\t\treturn nil, ensureErr\n\t\t}\n\n\t\tdestPath, ok := copied[absPath]\n\t\tif !ok {\n\t\t\tgroup := ExtractBoxIDFromAssetsPath(absPath)","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/clipboard.go#L65-L101","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nassets = append(assets, RichClipboardAsset{Index: -1, Path: p})\n\n// after\nfor i, p := range paths {\n    assets = append(assets, RichClipboardAsset{Index: i, Path: p})\n}","handlingStrategy":"validation","validationCode":"for i, a := range assets {\n    if a.Index < 0 { return fmt.Errorf(\"asset %d has invalid index %d\", i, a.Index) }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate indices from a loop counter, never hand-assign them","Avoid -1 as an 'unset' sentinel in serialized payloads; set the real position"],"tags":["clipboard","validation","index"],"backgroundTag":"argument-out-of-range","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}