{"record":{"id":"59f3086ebd696d92","repo":"siyuan-note/siyuan","slug":"data-block-dom-failed-w","errorCode":null,"errorMessage":"data block DOM failed: %w","messagePattern":"data block DOM failed: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/block_update.go","lineNumber":209,"sourceCode":"\t\t\t\tinvalidID = n.ID\n\t\t\t\treturn ast.WalkStop\n\t\t\t}\n\t\t\treturn ast.WalkContinue\n\t\t})\n\t}\n\tif \"\" != invalidID {\n\t\treturn \"\", errors.New(\"found invalid ID [\" + invalidID + \"]\")\n\t}\n\treturn\n}\n\nfunc parseBlockUpdateData(data, dataType string, luteEngine *lute.Lute) (ret string, tree *parse.Tree, err error) {\n\tret = data\n\tswitch dataType {\n\tcase \"markdown\":\n\t\tret, err = DataBlockDOM(data, luteEngine)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"data block DOM failed: %w\", err)\n\t\t\treturn\n\t\t}\n\tcase \"dom\":\n\tdefault:\n\t\terr = fmt.Errorf(\"unsupported block data type [%s]\", dataType)\n\t\treturn\n\t}\n\n\ttree = luteEngine.BlockDOM2Tree(ret)\n\tif nil == tree || nil == tree.Root || nil == firstContentBlock(tree.Root) {\n\t\terr = errors.New(\"parse tree failed\")\n\t}\n\treturn\n}\n\nfunc normalizeBlockUpdateTree(oldNode *ast.Node, tree *parse.Tree, luteEngine *lute.Lute) (ret *parse.Tree, updatedNode *ast.Node, err error) {\n\tupdatedNode, err = resolveBlockUpdateNode(oldNode, tree.Root)\n\tif err != nil {","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/block_update.go#L191-L227","documentation":"parseBlockUpdateData wraps errors from DataBlockDOM (the markdown-to-block-DOM conversion) with the context \"data block DOM failed\". It is thrown when markdown input supplied to buildBlockUpdateOperations cannot be converted to valid block DOM — most commonly because it contains an invalid explicit block ID (the wrapped error), or because the markdown itself fails conversion.","triggerScenarios":"Calling the block update flow (buildBlockUpdateOperations / /api/block/updateBlock) with dataType \"markdown\" where DataBlockDOM returns an error, e.g. markdown containing an explicit block ID that fails IsNodeIDPattern validation.","commonSituations":"API clients sending markdown with foreign/custom ID attributes; scripts updating blocks with content copied from other outliners that embed their own identifier syntax.","solutions":["Inspect the wrapped inner error (likely \"found invalid ID [...]\") and fix or remove the offending {: id=\"...\"} attribute in the markdown payload","Strip explicit block IDs and let SiYuan generate them during conversion","Validate markdown IDs client-side against the 14-character SiYuan ID pattern before calling the API"],"exampleFix":"// before\n{\"dataType\": \"markdown\", \"data\": \"text {: id=\\\"bad-id\\\"}\"}\n// after\n{\"dataType\": \"markdown\", \"data\": \"text\"}","handlingStrategy":"try-catch","validationCode":"if (payload.dataType === \"markdown\" && /\\{:\\s*id=\"(?!\\d{14}-[0-9a-z]{7}\")/.test(payload.data)) {\n  throw new Error(\"invalid explicit block ID in markdown payload\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  await updateBlock({ id, dataType: \"markdown\", data });\n} catch (e) {\n  if (String(e.msg).startsWith(\"data block DOM failed\")) {\n    // unwrap: usually \"found invalid ID [...]\" — sanitize data and retry\n  }\n}","preventionTips":["Read the wrapped inner error to identify the offending ID","Sanitize markdown IDs before every block update","Keep payloads free of foreign ID syntax from other tools"],"tags":["markdown","dom-conversion","api","wrapped-error"],"backgroundTag":"invalid-argument-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"}