siyuan-note/siyuan · error · Error

Unsupported shortcut binding version

Error message

Unsupported shortcut binding version

What it means

setKeymapBindings enforces that an IShortcutKeymap carrying a bindings object uses bindings.version === 1. If a bindings object exists with any other version, the library throws because it cannot safely interpret or migrate an unknown binding format. Maps without a bindings field are fine and are initialized to version 1.

Solutions

  1. Remove or reset the bindings field on the keymap item so it is regenerated as version 1
  2. Update the app to the version that wrote the newer bindings format
  3. Delete the stale keymap JSON and let the app rebuild default bindings
  4. Catch the error and reinitialize item.bindings to {version: 1} before retrying

Example fix

// before
setKeymapBindings(item, keys); // item.bindings.version === 2
// after
delete item.bindings; // or migrate version 2 to version 1
setKeymapBindings(item, keys);
Defensive patterns

Strategy: validation

Validate before calling

if (item.bindings && item.bindings.version !== 1) {
    delete item.bindings; // reset unknown format before calling
}
setKeymapBindings(item, keys);

Type guard

const isV1 = (item) => !item.bindings || item.bindings.version === 1;

Try / catch

try { setKeymapBindings(item, keys); } catch (e) { if (e.message.includes("binding version")) { delete item.bindings; setKeymapBindings(item, keys); } }

Prevention

When it happens

Trigger: Calling setKeymapBindings (app/src/util/keymapBindings.ts:47) with an item whose bindings.version is absent-but-object? no — present and not 1: e.g. bindings: {version: 2, ...} produced by a newer/older app version or hand-edited JSON in the keymap config.

Common situations: Downgrading the app after keymap format changed; merging keymap JSON from another user/installation; plugins or sync writing newer binding versions; hand-editing appearance config files.

Related errors


AI-assisted analysis of siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/ad9cc314a69ef61e. Report an issue: GitHub.

Appendix: source

Thrown at app/src/util/keymapBindings.ts:47

    bindings?: IShortcutBindings;
}

export const getKeymapBindings = (item?: IShortcutKeymap): string[] => {
    if (!item) {
        return [];
    }
    if (item.bindings) {
        if (item.bindings.version !== 1 || !Array.isArray(item.bindings.keys)) {
            return [];
        }
        return [...new Set(item.bindings.keys.filter((key): key is string => typeof key === "string" && key.length > 0))];
    }
    return typeof item.custom === "string" && item.custom ? [item.custom] : [];
};

export const setKeymapBindings = (item: IShortcutKeymap, keys: string[]) => {
    if (item.bindings && item.bindings.version !== 1) {
        throw new Error("Unsupported shortcut binding version");
    }
    const uniqueKeys = [...new Set(keys.filter(Boolean))];
    const priority = Object.fromEntries(Object.entries(item.bindings?.priority || {})
        .filter(([key]) => uniqueKeys.some(hotkey => key === hotkey || key.endsWith(":" + hotkey))));
    item.bindings = {...item.bindings, version: 1, keys: uniqueKeys, priority};
    item.custom = uniqueKeys[0] || "";
};

export const getKeymapItem = (keymap: object, path: readonly string[]): IShortcutKeymap | undefined => {
    let value: unknown = keymap;
    for (const key of path) {
        if (!value || typeof value !== "object" || !Object.prototype.hasOwnProperty.call(value, key)) {
            return undefined;
        }
        value = (value as Record<string, unknown>)[key];
    }
    return value && typeof value === "object" && typeof (value as IShortcutKeymap).custom === "string" ?
        value as IShortcutKeymap : undefined;

View on GitHub (pinned to 9f775e8a12)