Structural editors: cryptic/misleading Yjs encode error for invalid node JSON — pre-validate against the schema and report the offending node path #409
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
The structural editing tools (
patchNode,insertNode,tableUpdateCell,updatePageJson,transformPage) account for ~34 thrown failures in agent dialog history (2026-06-17…07-07 DB analysis, seedocs/reading-ai-logs.md), typically:Unknown node type: undefinedmeans a nested node in the agent-supplied JSON has notype(or an unknown type) — prosemirror'sSchema.nodeTypethrows it. Two code problems make the agent retry blind (UI logs show consecutive identical failures):patchNode(packages/mcp/src/client.ts:2087) checkstypeof node.type === "string"for the ROOT only; nestedcontentchildren are never validated. The error then surfaces deep in the Yjs encode, after the collab session is already open.findUnstorableAttr(packages/mcp/src/lib/node-ops.ts:331) only scansattrs/marksvalues for undefined/function/symbol/bigint — it cannot see a missing/unknowntype. SounstorableYjsError(packages/mcp/src/lib/collaboration.ts:31) falls through to the generic "A node/mark attribute likely holds a value Yjs cannot store" hint, pointing the model at attributes when the actual problem is a node shape (e.g.{"text": "foo"}missing"type": "text").Fix sketch
findInvalidNode(doc)walker innode-ops.ts: depth-first over the JSON; return the path and a short key summary of the first node whosetypeis not a string or not present indocmostSchema.nodes(and marks not indocmostSchema.marks), e.g.:node.content[2].content[0]: missing "type" (keys: text, marks) — did you mean {"type": "text", ...}?unstorableYjsError(collaboration.ts:31) BEFORE the attrs hint: checkfindInvalidNodefirst, fall back tofindUnstorableAttr, keep the generic sentence only as the last resort.patchNode/insertNode/updatePageJson(and the table-cell paragraph builder path): run the walker (ordocmostSchema.nodeFromJSON(target).check()in try/catch for full schema validation — nodeFromJSON gives precise PM errors) and throw the rich error BEFOREgetCollabTokenWithReauth/mutatePageContent. Fail fast: no collab session open, no page lock taken, deterministic message.packages/mcp/src/tool-specs.ts, patchNode/insertNode/updatePageJson): state explicitly that EVERY node, including nested children, must carry a stringtypefrom the Docmost schema, and that text leaves are{"type": "text", "text": "..."}.Notes
sanitizeForYjsalready stripsundefinedattr values — keep it; this issue is about the node-shape failure mode it cannot fix.transformPageexecutes agent-authored JS producing a doc — it benefits automatically from (1)+(2) since it shares the encode path.mutatePagenot called); unknown node type name → same; valid doc unaffected; findUnstorableAttr fallback still fires for a genuine undefined-attr case.