siyuan-note/siyuan · error · TypeError
The tracked range must contain semantic content
Error message
The tracked range must contain semantic content
What it means
trackRange precondition: the range to track contains no semantic content (e.g. an empty selection or only whitespace/formatting). Nothing meaningful would survive edit tracking, so the request is refused.
Source
Thrown at app/src/protyle/util/trackedRange.ts:1151
if (destroyedProtyles.has(protyle)) {
throw new Error("Cannot track a range in a destroyed Protyle instance");
}
if (!options?.owner || !["function", "object"].includes(typeof options.owner)) {
throw new TypeError("The tracked range owner is required");
}
if (options.affinity && !["after", "before"].includes(options.affinity)) {
throw new TypeError("The tracked range affinity must be before or after");
}
if (unloadingPlugins.has(options.owner)) {
throw new Error("Cannot track a range for an unloaded plugin");
}
const rangeSnapshot = getRangeSnapshot(protyle, range);
if (!rangeSnapshot) {
throw new TypeError("The range must be inside one editable source block of this Protyle instance");
}
const targetTokens = rangeSnapshot.stream.tokens.slice(rangeSnapshot.start, rangeSnapshot.end);
if (!range.collapsed && targetTokens.length === 0) {
throw new TypeError("The tracked range must contain semantic content");
}
const handle = Object.freeze({id: `tracked-range-${++handleSequence}`});
const trackedRange = range.cloneRange();
const state: ITrackedRangeState = {
range: trackedRange,
startContainer: trackedRange.startContainer,
endContainer: trackedRange.endContainer,
exactTarget: getExactlySelectedElement(trackedRange),
collapsed: trackedRange.collapsed,
affinity: options.affinity || "before",
targetTokens,
tokens: rangeSnapshot.stream.tokens,
start: rangeSnapshot.start,
end: rangeSnapshot.end,
sourceBlockID: rangeSnapshot.snapshot.block.getAttribute("data-node-id") || "",
sourceAncestorIDs: getAncestorBlockIDs(protyle.wysiwyg.element, rangeSnapshot.snapshot.block),
rootIDs: rangeSnapshot.stream.roots.map(root => root.getAttribute("data-node-id") || "").filter(Boolean),
rootBlockIDs: getRootBlockIDs(rangeSnapshot.stream.roots),View on GitHub (pinned to 8641553a1f)
Solutions
- Only track ranges with a non-empty selection
- Expand the selection to include the intended text node
- Skip tracking for caret-only positions
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at app/src/protyle/util/trackedRange.ts:1151 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/32d438bf57ff9af3.
Report an issue: GitHub.