siyuan-note/siyuan · error · Error

response.msg

Error message

response.msg

What it means

foldBlocksRecursively0 fetches all child DOM of a heading via /api/block/getHeadingChildrenDOM. When the kernel responds with a non-zero code, the raw response.msg text is thrown as an Error so the recursive fold operation aborts with the backend's message.

Solutions

  1. Catch the error in the fold action handler and show response.msg to the user, then refresh/ Reload the document to get fresh node IDs
  2. Re-index the notebook (Rebuild Index) if block IDs are stale due to index/database mismatch
  3. Retry the fold after the document tree has been refreshed so element carries a valid data-node-id
  4. Check kernel logs for the underlying error returned by getHeadingChildrenDOM

Example fix

// before
foldBlocksRecursively(protyle, element); // unhandled throw on API failure
// after
try {
  await foldBlocksRecursively(protyle, element);
} catch (e) {
  showMessage(e.message);
  reloadProtyle(protyle, false); // refresh stale DOM
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!element.getAttribute("data-node-id")) {
  throw new Error("Cannot fold: element has no data-node-id");
}

Type guard

const isApiResponse = (r: unknown): r is {code: number, msg: string, data: unknown} =>
  typeof r === "object" && r !== null && "code" in r && "msg" in r;

Try / catch

try {
  await foldBlocksRecursively(protyle, element);
} catch (e) {
  showMessage(e.message || "Fold failed");
  reloadProtyle(protyle, false);
}

Prevention

When it happens

Trigger: Calling foldBlocksRecursively on a NodeHeading whose /api/block/getHeadingChildrenDOM request fails — e.g. the block ID no longer exists (stale DOM), the notebook is closed/syncing, or the kernel returned an internal error for that block.

Common situations: Document changed in another window/sync while folding, leaving a stale data-node-id; kernel busy or restarting; database index out of sync with .sy files so the block lookup fails.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at app/src/protyle/util/blockFold.ts:330

    };
    const addScope = (scope: ParentNode, occurrenceID?: string) => {
        if (scope instanceof Element) {
            addCandidate(scope, occurrenceID);
        }
        scope.querySelectorAll("[data-type='NodeHeading'], .li, .bq, .sb, .callout").forEach(element => {
            addCandidate(element, occurrenceID);
        });
    };

    const scopes = await Promise.all(nodeElements.map(async (element) => {
        let fullHTML = "";
        if (element.getAttribute("data-type") === "NodeHeading") {
            const response = await fetchSyncPost("/api/block/getHeadingChildrenDOM", {
                id: element.getAttribute("data-node-id"),
                removeFoldAttr: false,
            });
            if (response.code !== 0) {
                throw new Error(response.msg);
            }
            fullHTML = response.data;
        } else if (element.querySelector('[data-type="NodeHeading"][fold="1"]')) {
            const response = await fetchSyncPost("/api/block/getBlockDOM", {
                id: element.getAttribute("data-node-id"),
                notebook: protyle.notebookId,
            });
            if (response.code !== 0) {
                throw new Error(response.msg);
            }
            fullHTML = response.data.dom;
        }
        return {element, fullHTML, occurrenceID: getViewFoldOccurrenceID(protyle, element)};
    }));
    scopes.forEach(({element, fullHTML, occurrenceID}) => {
        if (fullHTML) {
            const template = document.createElement("template");
            template.innerHTML = fullHTML;

View on GitHub (pinned to 9f775e8a12)