siyuan-note/siyuan · error · Error

response.msg

Error message

response.msg

What it means

In transaction.ts, the CancelListRecursively path queries /api/block/getBlockRelevantIDs to locate the previous block. A non-zero kernel response code causes the server's msg string to be thrown as an Error. This aborts the transaction preparation because the required previousID could not be resolved.

Solutions

  1. Refresh the editor DOM before the transaction so data-node-id is current
  2. Check the block exists via /api/block/getBlockInfo first and skip the operation if missing
  3. Catch the error, show a message, and re-open the document
  4. Retry after sync completes if concurrent modification caused the miss

Example fix

// before
await cancelListRecursively(protyle, nodeElement, options);
// after
try {
    await cancelListRecursively(protyle, nodeElement, options);
} catch (e) {
    showMessage(e.message);
    reloadProtyle(protyle);
}
Defensive patterns

Strategy: try-catch

Validate before calling

const check = await fetchSyncPost("/api/block/getBlockInfo", {id: nodeElement.getAttribute("data-node-id")});
if (check.code !== 0) return; // skip: block no longer exists

Try / catch

try { await prepareCancelListRecursively(...); } catch (e) { showMessage(e.message); reloadProtyle(protyle); }

Prevention

When it happens

Trigger: Executing a CancelListRecursively transaction (app/src/protyle/wysiwyg/transaction.ts:2071) when previousBlockElement is missing and protyle.block.showAll is on, and the node's data-node-id fails lookup in the kernel (block deleted, ID stale, notebook mismatch).

Common situations: Cancelling a list after a concurrent edit removed it via sync; stale DOM after undo/redo; the notebook was closed or its ID changed while the editor still references blocks in it.

Related errors


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

Appendix: source

Thrown at app/src/protyle/wysiwyg/transaction.ts:2071

    }
    if (!listElements[0].querySelector("wbr")) {
        getContenteditableElement(listElements[0])?.insertAdjacentHTML("afterbegin", "<wbr>");
    }
    options.nodeElements.forEach((nodeElement) => {
        nodeElement.classList.remove("protyle-wysiwyg--select");
        nodeElement.removeAttribute("select-start");
        nodeElement.removeAttribute("select-end");
    });
    const contexts = await Promise.all(listElements.map(async (nodeElement) => {
        const previousBlockElement = getPreviousBlockSibling(nodeElement);
        let previousId = previousBlockElement?.getAttribute("data-node-id");
        if (!previousBlockElement && options.type === "CancelListRecursively" && options.protyle.block.showAll) {
            const response = await fetchSyncPost("/api/block/getBlockRelevantIDs", {
                id: nodeElement.getAttribute("data-node-id"),
                notebook: options.protyle.notebookId,
            });
            if (response.code !== 0) {
                throw new Error(response.msg);
            }
            previousId = response.data.previousID;
        }
        return {
            id: nodeElement.getAttribute("data-node-id"),
            nodeElement,
            parentId: getEmbedChildOperationParentID(nodeElement) ||
                getParentBlock(nodeElement).getAttribute("data-node-id") ||
                options.protyle.block.parentID ||
                options.protyle.block.rootID,
            previousId,
        };
    }));
    const foldOperations = await unfoldListHeadings(options.protyle, listElements);
    const doOperations: IOperation[] = [];
    const undoOperations: IOperation[] = [];
    contexts.forEach((context) => {
        const nodeElement = context.nodeElement;

View on GitHub (pinned to 9f775e8a12)