Comfy-Org / Comfy-Org/ComfyUI_frontend

Preview exposures are never removed when their host SubgraphNode or interior source node is removed

Open
#15,715 0 comments 0 reactions 1 assignee Claimed by @DrJKL View on GitHub
area:previews area:subgraph Potential Bug
Dominant language
TypeScript
Stars
2k
Forks
699
Avg merge
1d 7h
Merged PRs (30d)
490

Description

Preview exposures in usePreviewExposureStore are only removed on explicit user demotion; no node-removal path cleans them. At `f1bfb313d6`, `removeExposure` has exactly two production callers, both demotion UI paths: `SubgraphEditor.vue:284` and `demoteWidget` (`promotionUtils.ts:462`). `LGraph.removeNode` (`LGraph.ts:1264-1315`) never touches the store.

Two orphan shapes:

1. Host SubgraphNode removed: exposures keyed `rootGraphId -> String(hostId)` are retained. Not re-serialized (serialization reads the store per live host, `SubgraphNode.ts:933-945`), so this shape is a session-scoped leak only.
2. Interior source node removed: the host's exposure keeps referencing a nonexistent `sourceNodeId`. Linked promotions have a pruning path (`pruneDisconnected`, `promotionUtils.ts:643-665`); exposures have no analogue. This shape DOES serialize with the host, so the dangling reference persists across save/load.

Bounded by the root clear: `LGraph.resetAfterClear` clears the store with the pre-reassignment root id (`LGraph.ts:575-582`) on every workflow switch/undo.

Pre-existing at the merge base (`a2603c59a6`), not introduced by #14246. Same lifecycle class as the promoted-WidgetState retention in #15714.

Suggested fix shape: shape 1 belongs next to the released-subgraph teardown in `LGraph.removeNode`; shape 2 needs an exposure-pruning analogue to `pruneDisconnected` on source-node removal, or a liveness filter at read/serialize time.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.