{"record":{"id":"1494329fd2449cda","repo":"siyuan-note/siyuan","slug":"invalid-attribute-view-rich-text-style-entity","errorCode":null,"errorMessage":"Invalid attribute view rich text style entity","messagePattern":"Invalid attribute view rich text style entity","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/protyle/render/av/richText.ts","lineNumber":253,"sourceCode":"            if (node.nodeType === Node.TEXT_NODE) {\n                node.nodeValue = replaceProtections(node.nodeValue || \"\", false, restored);\n                return;\n            }\n            node.childNodes.forEach(visit);\n        };\n        visit(element);\n    };\n    template.content.querySelectorAll('[data-type=\"NodeCodeBlock\"], span[data-type~=\"code\"]')\n        .forEach(restoreLiteralText);\n    template.content.querySelectorAll<HTMLElement>(\n        '[data-type=\"NodeMathBlock\"][data-content], [data-type=\"NodeMathBlock\"] [data-content], ' +\n        'span[data-type~=\"inline-math\"][data-content]'\n    ).forEach((element) => {\n        element.setAttribute(\"data-content\",\n            replaceProtections(element.getAttribute(\"data-content\") || \"\", false, restored));\n    });\n    if (protections.some((protection) => !restored.has(protection.token))) {\n        throw new Error(\"Invalid attribute view rich text style entity\");\n    }\n    return (template.innerHTML || \"\").trim();\n};\n\nconst parseAVRichTextKramdown = (markdown: string, lute = getAVRichTextLute()) => {\n    const protectedStyle = protectAVRichTextKramdownStyleEntities(markdown);\n    return restoreAVRichTextBlockDOMStyleEntities(lute.Md2BlockDOM(protectedStyle.content),\n        protectedStyle.protections);\n};\n\nconst getAVRichTextPlainContent = (blockDOM: string, lute: Lute) => {\n    const template = document.createElement(\"template\");\n    template.innerHTML = blockDOM;\n    const blocks = Array.from(template.content.querySelectorAll<HTMLElement>(\n        '[data-type=\"NodeParagraph\"], [data-type=\"NodeHeading\"], [data-type=\"NodeCodeBlock\"], ' +\n        '[data-type=\"NodeMathBlock\"]'\n    )).map((element) => lute.BlockDOM2Content(element.outerHTML));\n    return projectAVRichTextPlainBlocks(blocks, lute.BlockDOM2Content(blockDOM));","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/8641553a1f07374001902d3ce773285db1292b2d/app/src/protyle/render/av/richText.ts#L235-L271","documentation":"restoreAVRichTextBlockDOMStyleEntities renders attribute-view rich text kramdown by first protecting style-entity tokens (e.g. kramdown span/style entities) so the browser HTML parser cannot mangle them, then restoring them into the parsed DOM. After restoration it verifies that every protection token was actually restored into the template's DOM. If some tokens never reappear — meaning the parser dropped or altered the placeholder elements — this internal invariant is violated and the Error 'Invalid attribute view rich text style entity' is thrown from restoreAVRichTextBlockDOMStyleEntities.","triggerScenarios":"Call parseAVRichTextKramdown (e.g. while rendering an AV rich-text cell) with kramdown containing style-entity markup whose placeholder is lost during HTML parsing: the protected token's element is stripped, its data-content/protection attribute is dropped, or the markdown produces malformed HTML so the placeholder does not survive template parsing.","commonSituations":"Pasting kramdown text with broken or hand-edited style entities into an attribute-view rich text field; version changes in Lute or the sanitizer that alter how placeholders are parsed; programmatically injecting rich-text values with mismatched or duplicated style-entity tokens via the API or templates.","solutions":["Inspect the rich-text value's kramdown and fix or remove malformed style-entity spans so placeholders survive HTML parsing","Re-enter the affected rich-text cell content in the UI so the value is re-serialized into valid kramdown","If triggered after a Lute or SiYuan upgrade, report it — the protection/restoration round-trip invariant broke and the offending input should be captured","As a caller, wrap parseAVRichTextKramdown in try-catch and fall back to rendering the raw text instead of failing the whole cell"],"exampleFix":"// before: rendering crashes the whole AV cell\nconst html = parseAVRichTextKramdown(cellValue);\n// after: fall back to escaped text on invalid style entities\nlet html;\ntry {\n    html = parseAVRichTextKramdown(cellValue);\n} catch (e) {\n    html = escapeHtml(cellValue);\n}","handlingStrategy":"try-catch","validationCode":"// pre-validate that style-entity kramdown is well-formed before rendering\nconst hasBalancedStyleEntities = /\\{\\{[^{}]*\\}\\}/.test(markdown) === markdown.includes(\"{{\");\nif (markdown.includes(\"{{\") && !/\\{\\{[^{}]+\\}\\}/.test(markdown)) {\n    // malformed style entity — sanitize or reject before parseAVRichTextKramdown\n}","typeGuard":null,"tryCatchPattern":"let html;\ntry {\n    html = parseAVRichTextKramdown(markdown);\n} catch (e) {\n    if (e.message.includes(\"Invalid attribute view rich text style entity\")) {\n        html = escapeHtml(markdown); // degraded but safe rendering\n    } else {\n        throw e;\n    }\n}","preventionTips":["Never hand-edit kramdown style entities in AV rich text values; edit through the editor UI","When generating rich-text values programmatically, round-trip them through parseAVRichTextKramdown in tests before persisting","Keep SiYuan and Lute versions in sync; mismatched versions can break the protect/restore token round-trip","Sanitize pasted content containing {{ }} style-entity syntax before inserting it into AV rich text fields"],"tags":["av","rich-text","kramdown","parsing"],"backgroundTag":"internal-invariant-violation","analyzedSha":"8641553a1f07374001902d3ce773285db1292b2d","analyzedAt":"2026-09-11T16:08:28.414Z","contentChangedAt":"2026-09-11T16:08:28.414Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}