{"record":{"id":"f92655f0a15011d6","repo":"siyuan-note/siyuan","slug":"invalid-rich-clipboard-asset-at-index-d","errorCode":null,"errorMessage":"Invalid rich clipboard asset at index [%d]","messagePattern":"Invalid rich clipboard asset at index \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/apicontract/clipboard_input.go","lineNumber":33,"sourceCode":"\t\t\treturn request, err\n\t\t}\n\t\tassets, err := legacyField[[]json.RawMessage](fields, \"assets\", \"Array\", true)\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\tif len(assets) == 0 {\n\t\t\treturn request, fmt.Errorf(\"Field [assets] must not be empty\")\n\t\t}\n\t\trequest.Assets = make([]RichClipboardAsset, 0, len(assets))\n\t\tfor i, raw := range assets {\n\t\t\tvar asset map[string]json.RawMessage\n\t\t\tif json.Unmarshal(raw, &asset) != nil || asset == nil {\n\t\t\t\treturn request, fmt.Errorf(\"Field [assets.%d] should be of type [Object]\", i)\n\t\t\t}\n\t\t\tvar index float64\n\t\t\tvar path, box string\n\t\t\tif 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) == \"\" {\n\t\t\t\treturn request, fmt.Errorf(\"Invalid rich clipboard asset at index [%d]\", i)\n\t\t\t}\n\t\t\tif value, exists := asset[\"box\"]; exists {\n\t\t\t\tif bytes.Equal(value, []byte(\"null\")) || json.Unmarshal(value, &box) != nil {\n\t\t\t\t\treturn request, fmt.Errorf(\"Field [assets.%d.box] should be of type [String]\", i)\n\t\t\t\t}\n\t\t\t}\n\t\t\trequest.Assets = append(request.Assets, RichClipboardAsset{Index: int(index), Path: strings.TrimSpace(path), Box: strings.TrimSpace(box)})\n\t\t}\n\t\treturn\n\t}\n\tCleanupRichText.decodeRequest = func(reader io.Reader) (request CleanupRichTextRequest, err error) {\n\t\tfields, err := blockRequestFields(reader, \"/api/clipboard/cleanupRichText\")\n\t\tif err != nil {\n\t\t\treturn request, err\n\t\t}\n\t\trequest.Batch, err = legacyField[string](fields, \"batch\", \"String\", true)\n\t\tif err != nil {\n\t\t\treturn request, err","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/apicontract/clipboard_input.go#L15-L51","documentation":"Each rich clipboard asset must carry a non-negative integer index and a non-empty string path; an optional box must be usable as context. This aggregate check fires when index is null/non-numeric/negative/fractional, or path is missing, non-string, or whitespace-only.","triggerScenarios":"Sending an asset like {\"index\":-1,\"path\":\"/a.png\"} (negative index), {\"index\":1.5,\"path\":\"/a.png\"} (non-integer), {\"index\":0} (missing path), or {\"index\":0,\"path\":\"   \"} (blank path) to /api/clipboard/prepareRichText.","commonSituations":"Client computes index from a zero-based vs one-based list inconsistently; asset path built from an empty variable; floats leaking from JavaScript arithmetic producing 0.30000000000000004-style indices.","solutions":["Ensure index is a non-negative integer (Math.floor / Math.trunc it before sending)","Ensure path is a non-empty, non-whitespace string (trim it; it is trimmed server-side anyway)","Include every required key (index, path) in each asset object; box is the only optional key"],"exampleFix":"// before\n{index: 1.5, path: \"\"}\n// after\n{index: 1, path: \"/assets/foo.png\"}","handlingStrategy":"validation","validationCode":"for (const [i, a] of assets.entries()) {\n  if (!Number.isInteger(a.index) || a.index < 0) throw new Error(`assets[${i}].index must be a non-negative integer`);\n  if (typeof a.path !== 'string' || !a.path.trim()) throw new Error(`assets[${i}].path must be a non-empty string`);\n}","typeGuard":"const isValidAsset = (a) => a && Number.isInteger(a.index) && a.index >= 0 && typeof a.path === 'string' && a.path.trim() !== '';","tryCatchPattern":null,"preventionTips":["Math.floor computed indices before sending","Trim paths client-side; never send whitespace-only paths","Always include index and path; box is the only optional key"],"tags":["validation","clipboard","request-body"],"backgroundTag":"invalid-argument-value","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"}