{"record":{"id":"48597688ef55d7e6","repo":"siyuan-note/siyuan","slug":"invalid-attribute-view-source-d","errorCode":null,"errorMessage":"invalid attribute view source [%d]","messagePattern":"invalid attribute view source \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view.go","lineNumber":6071,"sourceCode":"}\n\nfunc addAttributeViewBlocks(tx *Transaction, srcs []map[string]any, avID, dbBlockID, viewID, groupID, previousItemID string, ignoreDefaultFill bool) (result *insertAttrViewBlockResult, err error) {\n\tresult = &insertAttrViewBlockResult{}\n\tif 0 == len(srcs) {\n\t\treturn\n\t}\n\tslices.Reverse(srcs) // https://github.com/siyuan-note/siyuan/issues/11286\n\tattrView, err := avParseView(avID, dbBlockID)\n\tif err != nil {\n\t\treturn\n\t}\n\n\t// 整批校验完成后再写入，避免后续条目越界时已修改前面的绑定。\n\tboundTrees := map[string]*parse.Tree{}\n\tdetachedSources := make([]bool, len(srcs))\n\tfor index, src := range srcs {\n\t\tif nil == src {\n\t\t\treturn result, fmt.Errorf(\"invalid attribute view source [%d]\", index)\n\t\t}\n\t\t// 绑定条目的序列化数据可能省略值为 false 的字段，撤销重放时按绑定状态读取。\n\t\tisDetached, ok := src[\"isDetached\"].(bool)\n\t\tif !ok && nil != src[\"isDetached\"] {\n\t\t\treturn result, fmt.Errorf(\"invalid attribute view source [%d]: isDetached must be a boolean\", index)\n\t\t}\n\t\tdetachedSources[index] = isDetached\n\t\tif isDetached {\n\t\t\tcontinue\n\t\t}\n\t\tid, ok := src[\"id\"].(string)\n\t\tif !ok {\n\t\t\treturn result, fmt.Errorf(\"invalid attribute view source [%d]: id must be a string\", index)\n\t\t}\n\t\tif !ast.IsNodeIDPattern(id) {\n\t\t\tcontinue\n\t\t}\n\t\tvar tree *parse.Tree","sourceCodeStart":6053,"sourceCodeEnd":6089,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view.go#L6053-L6089","documentation":"During batch rebinding of attribute-view sources, each entry of the srcs array is checked before any write happens. A nil entry (or an entry that is not an object) aborts the whole batch with this error, reporting the offending index. Validation completes for all entries before any tree is modified.","triggerScenarios":"Calling the batch bind/detach API with a srcs array containing a null element at position N — typically produced by serializing entries where undefined became null, or by building the array programmatically with a skipped item.","commonSituations":"A plugin constructs the payload with JSON.stringify where undefined entries collapse to null; an off-by-one loop appends an empty slot; a client passes raw JSON with null placeholders.","solutions":["Filter out null/undefined entries from srcs before sending the request","Fix the payload-building loop so every index holds a valid object ({id, isDetached, ...})","Log the reported index and inspect that element of the request body"],"exampleFix":"// before\napi.bindAttributeView(sources); // sources[2] === null\n// after\nconst valid = sources.filter(Boolean);\napi.bindAttributeView(valid);","handlingStrategy":"validation","validationCode":"const clean = (srcs ?? []).filter(s => s !== null && s !== undefined && typeof s === 'object');\nif (clean.length !== srcs.length) console.warn('dropped null attribute-view source entries');","typeGuard":"function isValidSource(s) { return s !== null && s !== undefined && typeof s === 'object'; }","tryCatchPattern":"try {\n  await api.bindAttributeViewSources(srcs);\n} catch (e) {\n  if (/invalid attribute view source \\[\\d+\\]$/.test(e.message)) {\n    const idx = +e.message.match(/\\[(\\d+)\\]/)[1];\n    srcs = srcs.filter((_, i) => i !== idx);\n  } else { throw e; }\n}","preventionTips":["Filter null/undefined from arrays before serializing request payloads","Avoid building arrays with possible empty slots (use push/filter, not index assignment)","Validate the full batch payload client-side before sending"],"tags":["attribute-view","validation","batch","argument"],"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"}