Removing the last edge from a flow_diagram block makes the block fail to render with Cannot read properties of undefined (reading 'from').
Repro (Whiteboard Desktop 0.1.1, via MCP)
session_edit insert:
{"type":"flow_diagram","title":"Repro flow",
"nodes":[{"key":"a","label":"A"},{"key":"b","label":"B"},{"key":"c","label":"C"}],
"edges":[{"from":"a","to":"b"},{"from":"b","to":"c"},{"from":"a","to":"c"}]}
- After the diagram renders,
session_edit {"type":"remove","targetId":"<id of the a→c edge>"}.
- The block renders "This flow diagram block could not be rendered: Cannot read properties of undefined (reading 'from')".
Before (3 edges) → after removing a→c:

Cause
FlowGraph keeps the previous layout in state while layoutFlow runs for the new block (flow-graph.tsx#L60-L74). On the render right after the edit, the edges memo pairs the new block with the old layout and indexes by the old edge positions (flow-graph.tsx#L107-L124):
source: block.edges[edge.index]!.from,
edge.index comes from the ELK id assigned against the old edge array (flow-graph.tsx#L267-L270, #L304), so index 2 is out of bounds once the block has two edges. The ! hides this from the type checker. (From reading the code, removing a middle edge wouldn't throw, but that one frame would pair edges with the wrong endpoints/labels. I haven't verified this.)
Possible fix
Keep the block a layout was computed for next to the layout, and treat a mismatch as "not laid out yet", e.g. setLayout({ block, result }), then const current = layout?.block === block ? layout.result : undefined.
Removing the last edge from a
flow_diagramblock makes the block fail to render withCannot read properties of undefined (reading 'from').Repro (Whiteboard Desktop 0.1.1, via MCP)
session_editinsert:{"type":"flow_diagram","title":"Repro flow", "nodes":[{"key":"a","label":"A"},{"key":"b","label":"B"},{"key":"c","label":"C"}], "edges":[{"from":"a","to":"b"},{"from":"b","to":"c"},{"from":"a","to":"c"}]}session_edit{"type":"remove","targetId":"<id of the a→c edge>"}.Before (3 edges) → after removing
a→c:Cause
FlowGraphkeeps the previouslayoutin state whilelayoutFlowruns for the new block (flow-graph.tsx#L60-L74). On the render right after the edit, theedgesmemo pairs the newblockwith the old layout and indexes by the old edge positions (flow-graph.tsx#L107-L124):edge.indexcomes from the ELK id assigned against the old edge array (flow-graph.tsx#L267-L270, #L304), so index 2 is out of bounds once the block has two edges. The!hides this from the type checker. (From reading the code, removing a middle edge wouldn't throw, but that one frame would pair edges with the wrong endpoints/labels. I haven't verified this.)Possible fix
Keep the block a layout was computed for next to the layout, and treat a mismatch as "not laid out yet", e.g.
setLayout({ block, result }), thenconst current = layout?.block === block ? layout.result : undefined.