siyuan-note/siyuan · error · TypeError

The tracked range owner is required

Error message

The tracked range owner is required

What it means

Thrown by trackRange when options.owner is missing or is not a function or object. The owner identifies which plugin/component owns the tracked range so ranges can be cleaned up on unload; tracking without an owner would leak. It is a TypeError because it is a malformed-argument problem, not a state problem.

Source

Thrown at app/src/protyle/util/trackedRange.ts:1137

        const handles = ownedHandles.get(state.owner);
        handles?.forEach(item => {
            if (item.protyle === protyle && item.handle === handle) {
                handles.delete(item);
            }
        });
        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 = {

View on GitHub (pinned to 8641553a1f)

Solutions

  1. Pass the plugin instance (or a function/object owner) as options.owner: trackRange(protyle, range, {owner: this})
  2. If your owner is a string ID, wrap it in an object or use the plugin object itself
  3. Add a default in your wrapper so owner is always supplied
  4. Check the current ITrackRangeOptions signature and update call sites

Example fix

// before
trackRange(protyle, range, {owner: "my-plugin"});
// after
trackRange(protyle, range, {owner: this /* plugin instance */});
Defensive patterns

Strategy: validation

Validate before calling

function assertOwner(owner: unknown): asserts owner is object | ((...a: unknown[]) => unknown) {
  if (!owner || !["function", "object"].includes(typeof owner)) {
    throw new TypeError("tracked range owner required");
  }
}

Type guard

const hasOwner = (o: ITrackRangeOptions | undefined): o is ITrackRangeOptions & {owner: object | ((...a: unknown[]) => unknown)} =>
  !!o && ["function", "object"].includes(typeof o.owner) && o.owner != null;

Try / catch

try {
  trackRange(protyle, range, opts);
} catch (e) {
  if (e instanceof TypeError && e.message.includes("owner is required")) {
    console.error("trackRange called without a valid owner");
  } else throw e;
}

Prevention

When it happens

Trigger: Calling trackRange(protyle, range) with no options object, options: undefined/null, or options.owner set to undefined/null/string/number/boolean.

Common situations: Migrating code written against an older trackRange signature without options; passing plugin.name (a string) instead of the plugin instance; forgetting the options argument entirely.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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