siyuan-note/siyuan · error

inconsistent attribute view rich text style entity sentinel

Error message

inconsistent attribute view rich text style entity sentinel

What it means

During restoration of protected style entities in an attribute view rich text tree, every protection entry must carry the same sentinel marker that was generated when the entities were protected. restoreValueTextRichTreeStyleEntities derives the expected sentinel from protections[0] and rejects the batch if any later entry carries a different sentinel. This is an internal invariant: protections are always created together by protectValueTextRichStyleEntities, so a mismatch means the slice was assembled or mutated incorrectly.

Source

Thrown at kernel/av/value.go:1921

	}
	return builder.String(), protections
}

func restoreValueTextRichTreeStyleEntities(tree *parse.Tree,
	protections []valueTextRichStyleEntityProtection) (err error) {
	if 1 > len(protections) {
		return
	}
	sentinel := protections[0].sentinel
	stylePairs := make([]string, 0, len(protections)*2)
	literalPairs := make([]string, 0, len(protections)*2)
	textMarkCodePairs := make([]string, 0, len(protections)*2)
	textMarkInlineMathPairs := make([]string, 0, len(protections)*2)
	tokenIndexes := make(map[string]int, len(protections))
	restored := make([]bool, len(protections))
	for i, protection := range protections {
		if sentinel != protection.sentinel {
			return fmt.Errorf("inconsistent attribute view rich text style entity sentinel")
		}
		tokenIndexes[protection.token] = i
		stylePairs = append(stylePairs, protection.token, protection.decoded)
		literalPairs = append(literalPairs, protection.token, protection.encoded)
		encoded := strings.ReplaceAll(protection.encoded, "&", "&")
		textMarkCodePairs = append(textMarkCodePairs, protection.token, encoded)
		textMarkInlineMathPairs = append(textMarkInlineMathPairs, protection.token,
			strings.ReplaceAll(encoded, "&", "&"))
	}
	styleReplacer := strings.NewReplacer(stylePairs...)
	literalReplacer := strings.NewReplacer(literalPairs...)
	textMarkCodeReplacer := strings.NewReplacer(textMarkCodePairs...)
	textMarkInlineMathReplacer := strings.NewReplacer(textMarkInlineMathPairs...)

	ast.Walk(tree.Root, func(node *ast.Node, entering bool) ast.WalkStatus {
		if !entering {
			return ast.WalkContinue
		}

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Ensure all protections passed to restoreValueTextRichTreeStyleEntities come from a single protectValueTextRichStyleEntities run over the same content
  2. Verify the sentinel field of every protection entry matches protections[0].sentinel before calling the restore function
  3. If merging content, re-run protection and restoration as one unified pass instead of stitching slices

Example fix

// before
protections = append(oldProtections, newProtections...)
restoreValueTextRichTreeStyleEntities(tree, protections)
// after
allProtected, _ := protectValueTextRichStyleEntities(combinedStyle, sentinel, offset)
restoreValueTextRichTreeStyleEntities(tree, allProtected)
Defensive patterns

Strategy: validation

Validate before calling

const sentinel0 = protections[0]?.sentinel
if (!protections.every(p => p.sentinel === sentinel0)) {
  throw new Error("mixed sentinel protection sets; re-run protection in a single pass")
}

Prevention

When it happens

Trigger: Calling restoreValueTextRichTreeStyleEntities (via the rich text normalization path, e.g. NormalizeValueTextRich on a ValueText with a rich payload) with a protections slice whose entries were produced by different protectValueTextRichStyleEntities invocations, or with a programmatically modified slice where one entry's sentinel field differs from the first entry's.

Common situations: Kernel-side code combining protection slices from two separate protect passes; tests or tooling that hand-construct valueTextRichStyleEntityProtection entries with mismatched sentinel strings; a partial refactor that re-protects part of a document under a new sentinel but restores with the old slice.

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/fc2e994e84ff2808. Report an issue: GitHub.