{"record":{"id":"74e4fc437d2023e4","repo":"siyuan-note/siyuan","slug":"invalid-rich-clipboard-asset-count-d","errorCode":null,"errorMessage":"invalid rich clipboard asset count [%d]","messagePattern":"invalid rich clipboard asset count \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/clipboard.go","lineNumber":68,"sourceCode":"\tIndex int\n\tPath  string\n\tBox   string\n}\n\ntype RichClipboardPreparedAsset struct {\n\tIndex int    `json:\"index\"`\n\tPath  string `json:\"path\"`\n}\n\ntype RichClipboardPrepared struct {\n\tBatch  string                       `json:\"batch\"`\n\tGroups []string                     `json:\"groups\"`\n\tAssets []RichClipboardPreparedAsset `json:\"assets\"`\n}\n\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)))","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/clipboard.go#L50-L86","documentation":"Returned by PrepareRichClipboardAssets when the number of assets supplied in the slice is less than 1 or greater than 1024. The function performs a bounded batch copy of image assets for rich clipboard pasting and rejects empty or oversized batches up front to cap memory and I/O. The %d placeholder is filled with len(assets).","triggerScenarios":"Calling PrepareRichClipboardAssets with an empty slice, or with a slice containing more than 1024 image references (e.g. pasting a document that embeds hundreds of inline images). The check is the very first guard in the function, before any disk work.","commonSituations":"Frontend paste handler sends an empty assets array because the clipboard contained no images; a large page copy triggers hundreds of embedded images exceeding the 1024 cap; a bug in asset collection produces a nil/empty slice.","solutions":["Skip the call entirely when the assets slice is empty (guard with len(assets) == 0 before invoking).","If the batch exceeds 1024, chunk the assets into multiple batches of <=1024 and call PrepareRichClipboardAssets per chunk.","Audit the frontend code that builds the assets array to ensure it only includes genuine image references."],"exampleFix":"// before\nprepared, err := PrepareRichClipboardAssets(assets)\n\n// after\nif len(assets) == 0 {\n    return // nothing to do\n}\nfor i := 0; i < len(assets); i += 1024 {\n    end := i + 1024\n    if end > len(assets) {\n        end = len(assets)\n    }\n    prepared, err := PrepareRichClipboardAssets(assets[i:end])\n    // handle prepared, err\n}","handlingStrategy":"validation","validationCode":"// Validate count before calling PrepareRichClipboardAssets\nconst maxRichClipboardAssets = 1024\nif len(assets) == 0 || len(assets) > maxRichClipboardAssets {\n    // chunk or skip\n}","typeGuard":"func isValidRichClipboardCount(n int) bool { return n >= 1 && n <= 1024 }","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"invalid rich clipboard asset count\") { /* chunk or abort */ }","preventionTips":["Skip the call for empty asset slices.","Chunk large pastes into batches of at most 1024 assets.","Audit the frontend asset collector to avoid oversized batches."],"tags":["clipboard","assets","validation","batching","limits"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}