siyuan-note/siyuan · error
Cannot track a range for an unloaded plugin
Error message
Cannot track a range for an unloaded plugin
What it means
trackRange precondition: options.owner is registered in unloadingPlugins, i.e. the plugin that would own the tracked range is mid-unload. Tracking a range on behalf of a plugin being unloaded would leak a handle nobody can release, so it is refused.
Source
Thrown at app/src/protyle/util/trackedRange.ts:1143
if (handles?.size === 0) {
ownedHandles.delete(state.owner);
}
}
};
export const trackRange = (protyle: IProtyle, range: Range,
options: ITrackRangeOptions): ITrackedRangeHandle => {
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",View on GitHub (pinned to 8641553a1f)
Solutions
- Stop creating tracked ranges during plugin unload
- Release existing handles in the plugin's onUnload callback
- Re-track after the plugin is fully re-loaded
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at app/src/protyle/util/trackedRange.ts:1143 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/b5d471a18c244627.
Report an issue: GitHub.