{"record":{"id":"ca77a9ce1862fcd4","repo":"siyuan-note/siyuan","slug":"invalid-block-id-s","errorCode":null,"errorMessage":"invalid block ID [%s]","messagePattern":"invalid block ID \\[(.+?)\\]","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/block_update.go","lineNumber":93,"sourceCode":"\n\ttransaction := &Transaction{DoOperations: operations}\n\tif err = performTxSyncLocked(transaction); err != nil {\n\t\treturn nil, nil, err\n\t}\n\treturn []*Transaction{transaction}, rootIDs, nil\n}\n\nfunc buildBlockUpdateOperations(inputs []BlockUpdateInput, resolveTree blockUpdateTreeResolver, loadTree blockUpdateTreeLoader) (operations []*Operation, rootIDs []string, err error) {\n\tif 1 > len(inputs) {\n\t\treturn nil, nil, errors.New(\"block updates are empty\")\n\t}\n\n\tluteEngine := util.NewLute()\n\trootIDSet := map[string]struct{}{}\n\ttreeCache := map[blockUpdateTreeKey]*parse.Tree{}\n\tfor _, input := range inputs {\n\t\tif !ast.IsNodeIDPattern(input.ID) {\n\t\t\treturn nil, nil, fmt.Errorf(\"invalid block ID [%s]\", input.ID)\n\t\t}\n\n\t\tdata, dataTree, parseErr := parseBlockUpdateData(input.Data, input.DataType, luteEngine)\n\t\tif parseErr != nil {\n\t\t\treturn nil, nil, parseErr\n\t\t}\n\n\t\tvar oldTree *parse.Tree\n\t\tvar cacheKey blockUpdateTreeKey\n\t\thasCacheKey := false\n\t\tif blockTree := resolveTree(input.ID); nil != blockTree {\n\t\t\tcacheKey = blockUpdateTreeKey{boxID: blockTree.BoxID, rootID: blockTree.RootID}\n\t\t\thasCacheKey = true\n\t\t\toldTree = treeCache[cacheKey]\n\t\t}\n\t\tif nil == oldTree {\n\t\t\tvar loadErr error\n\t\t\toldTree, loadErr = loadTree(input.ID)","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/block_update.go#L75-L111","documentation":"buildBlockUpdateOperations validates every input's ID against ast.IsNodeIDPattern before parsing its data; an ID that does not match the SiYuan node ID format aborts the whole batch with \"invalid block ID [%s]\". IDs are updatable-14 style identifiers and the kernel refuses to operate on anything else.","triggerScenarios":"Passing a hand-composed, truncated, whitespace-padded, or empty string as a block ID in a BlockUpdateInput; sending DOM-derived ids that were mangled or placeholder values like \"new-block\".","commonSituations":"Scripts generating IDs themselves instead of reading them from the kernel; ids copied with surrounding quotes/whitespace from logs; tests using obviously fake identifiers.","solutions":["Use real IDs returned by the kernel (getBlockInfo, query/sql, editor state) — never generate them client-side.","Validate the ID format before sending (see validation code below).","Trim whitespace and strip quotes/brackets from IDs parsed out of logs or DOM attributes."],"exampleFix":"// before\nawait updateBlock({ id: '  20240101120000-abc1234  ', data: md });\n// after\nconst id = rawId.trim();\nif (!/^[0-9]{14}-[a-z0-9]{7}$/.test(id)) throw new Error(`invalid block id: ${rawId}`);\nawait updateBlock({ id, data: md });","handlingStrategy":"validation","validationCode":"function isValidBlockId(id) {\n  return typeof id === 'string' && /^[0-9]{14}-[a-z0-9]{7}$/.test(id.trim());\n}","typeGuard":"function asBlockId(v) {\n  return typeof v === 'string' && /^[0-9]{14}-[a-z0-9]{7}$/.test(v.trim()) ? v.trim() : null;\n}","tryCatchPattern":"try { await updateBlocks(inputs); } catch (e) { if (String(e.msg).includes('invalid block ID')) console.error('fix id source; ids must come from the kernel'); throw e; }","preventionTips":["Never fabricate or derive block IDs client-side; read them from API responses or data-id attributes.","Trim and strip quotes/brackets when extracting IDs from logs or DOM.","Validate ID format before adding to a batch."],"tags":["invalid-id","validation","block-update","kernel"],"backgroundTag":"invalid-identifier-format","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"}