{"record":{"id":"cb9881bf1be90ae1","repo":"siyuan-note/siyuan","slug":"response-msg-transaction","errorCode":null,"errorMessage":"response.msg","messagePattern":"response\\.msg","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"app/src/protyle/wysiwyg/transaction.ts","lineNumber":2071,"sourceCode":"    }\n    if (!listElements[0].querySelector(\"wbr\")) {\n        getContenteditableElement(listElements[0])?.insertAdjacentHTML(\"afterbegin\", \"<wbr>\");\n    }\n    options.nodeElements.forEach((nodeElement) => {\n        nodeElement.classList.remove(\"protyle-wysiwyg--select\");\n        nodeElement.removeAttribute(\"select-start\");\n        nodeElement.removeAttribute(\"select-end\");\n    });\n    const contexts = await Promise.all(listElements.map(async (nodeElement) => {\n        const previousBlockElement = getPreviousBlockSibling(nodeElement);\n        let previousId = previousBlockElement?.getAttribute(\"data-node-id\");\n        if (!previousBlockElement && options.type === \"CancelListRecursively\" && options.protyle.block.showAll) {\n            const response = await fetchSyncPost(\"/api/block/getBlockRelevantIDs\", {\n                id: nodeElement.getAttribute(\"data-node-id\"),\n                notebook: options.protyle.notebookId,\n            });\n            if (response.code !== 0) {\n                throw new Error(response.msg);\n            }\n            previousId = response.data.previousID;\n        }\n        return {\n            id: nodeElement.getAttribute(\"data-node-id\"),\n            nodeElement,\n            parentId: getEmbedChildOperationParentID(nodeElement) ||\n                getParentBlock(nodeElement).getAttribute(\"data-node-id\") ||\n                options.protyle.block.parentID ||\n                options.protyle.block.rootID,\n            previousId,\n        };\n    }));\n    const foldOperations = await unfoldListHeadings(options.protyle, listElements);\n    const doOperations: IOperation[] = [];\n    const undoOperations: IOperation[] = [];\n    contexts.forEach((context) => {\n        const nodeElement = context.nodeElement;","sourceCodeStart":2053,"sourceCodeEnd":2089,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/app/src/protyle/wysiwyg/transaction.ts#L2053-L2089","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Refresh the editor DOM before the transaction so data-node-id is current","Check the block exists via /api/block/getBlockInfo first and skip the operation if missing","Catch the error, show a message, and re-open the document","Retry after sync completes if concurrent modification caused the miss"],"exampleFix":"// before\nawait cancelListRecursively(protyle, nodeElement, options);\n// after\ntry {\n    await cancelListRecursively(protyle, nodeElement, options);\n} catch (e) {\n    showMessage(e.message);\n    reloadProtyle(protyle);\n}","handlingStrategy":"try-catch","validationCode":"const check = await fetchSyncPost(\"/api/block/getBlockInfo\", {id: nodeElement.getAttribute(\"data-node-id\")});\nif (check.code !== 0) return; // skip: block no longer exists","typeGuard":null,"tryCatchPattern":"try { await prepareCancelListRecursively(...); } catch (e) { showMessage(e.message); reloadProtyle(protyle); }","preventionTips":["Refresh editor DOM before transactions in showAll mode","Pre-check the block ID via getBlockInfo","Retry after sync settles in multi-device setups"],"tags":["api","transaction","block-not-found"],"backgroundTag":"api-error-response","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}