siyuan-note/siyuan · error
attribute view rich text style entity was not restored
Error message
attribute view rich text style entity was not restored
What it means
After walking the tree and applying all replacements, at least one protection entry was never marked as restored: its token never appeared (in a valid form) anywhere in the tree. Every protection created during the protect phase must be consumed exactly once; an unconsumed token means content was lost or the tree does not correspond to the protection set.
Source
Thrown at kernel/av/value.go:2001
switch node.Type {
case ast.NodeCodeBlockCode, ast.NodeMathBlockContent, ast.NodeCodeSpanContent, ast.NodeInlineMathContent:
if !markValueTextRichStyleProtections(tokens, sentinel, tokenIndexes, restored) {
err = fmt.Errorf("invalid encoded style entity in attribute view rich text node [%s]", node.Type.String())
return ast.WalkStop
}
node.Tokens = []byte(literalReplacer.Replace(tokens))
default:
err = fmt.Errorf("invalid encoded style entity in attribute view rich text node [%s]", node.Type.String())
return ast.WalkStop
}
return ast.WalkContinue
})
if nil != err {
return
}
for _, found := range restored {
if !found {
return fmt.Errorf("attribute view rich text style entity was not restored")
}
}
ast.Walk(tree.Root, func(node *ast.Node, entering bool) ast.WalkStatus {
if entering && valueTextRichNodeContainsSentinel(node, sentinel) {
err = fmt.Errorf("attribute view rich text style entity sentinel was not removed from node [%s]",
node.Type.String())
return ast.WalkStop
}
return ast.WalkContinue
})
return
}
func valueTextRichNodeContainsSentinel(node *ast.Node, sentinel string) bool {
values := []string{
node.ID, node.Spec, node.Data, string(node.Tokens), string(node.CodeBlockOpenFence),
string(node.CodeBlockInfo), string(node.CodeBlockCloseFence), string(node.LinkRefLabel),
string(node.FootnotesRefLabel), node.FootnotesRefId, string(node.HtmlEntityTokens),View on GitHub (pinned to 8641553a1f)
Solutions
- Inspect the rich text for styled spans that the Kramdown parser drops or rewrites (malformed HTML, unsupported attributes) and fix them
- Re-author the value so protected entities live in constructs that survive a parse/render round trip
- Verify the protection set matches the tree actually being restored (same pass, same content)
Defensive patterns
Strategy: try-catch
Validate before calling
// pre-check: styled spans must be constructs the Kramdown parser preserves
for (const span of styledSpans(tree)) {
if (!/^<span\s+[^>]*style=/.test(span.raw)) {
throw new Error("styled content uses a construct that may not round-trip")
}
} Try / catch
try {
await api.normalizeAvValueText(payload)
} catch (e) {
if (String(e).includes("style entity was not restored")) {
payload = rebuildRichTextWithoutDroppedSpans(payload)
await api.normalizeAvValueText(payload)
}
} Prevention
- Author rich text only with supported Kramdown constructs
- Fix malformed HTML spans that the parser silently drops
- Test round-trip stability of complex styled content before saving
When it happens
Trigger: Normalizing rich text where the protect pass created tokens for style entities but a later parse/render step dropped or transformed the containing node (e.g. Lute normalized away the styled span), leaving the token unused.
Common situations: Style entities inside constructs that get rewritten during Kramdown round-tripping (e.g. invalid HTML that the parser discards); content where a styled span was removed by normalization before restoration ran.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- ErrRichTextSpecMismatch
- unsupported attribute view rich text spec [%d]
- unsupported attribute view rich text format [%s]
- parse attribute view rich text failed
- attribute view rich text tree is missing
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/1453fae0c2b77c79.
Report an issue: GitHub.